目录:
- [Mybatis的核心配置 :](#Mybatis的核心配置 :)
-
- [一、MyBatis的 "核心对象"](#一、MyBatis的 “核心对象”)
-
- [1.1 SqlSessionFactory](#1.1 SqlSessionFactory)
- [1.2 SqlSession :](#1.2 SqlSession :)
-
- [SqlSession对象中的操作数据库的方法 :](#SqlSession对象中的操作数据库的方法 :)
-
- [\<T> T selectOne ( String statement )](#<T> T selectOne ( String statement ))
- [\<T> T selectOne( String statement , Object parameter )](#<T> T selectOne( String statement , Object parameter ))
- [\<E> List\<E> selectList ( String statement )](#<E> List<E> selectList ( String statement ))
- [\<E> List\<E> selectList ( String statement , Object parameter )](#<E> List<E> selectList ( String statement , Object parameter ))
- [\<E> List\<E> selectList ( String statement , Object parameter , RowBounds rowBounds )](#<E> List<E> selectList ( String statement , Object parameter , RowBounds rowBounds ))
- [void select ( String statement , Object parameter , ResultHandler handler )](#void select ( String statement , Object parameter , ResultHandler handler ))
- [int insert ( String statement )](#int insert ( String statement ))
- [int insert ( String statement , Object parameter )](#int insert ( String statement , Object parameter ))
- [int update( String statement )](#int update( String statement ))
- [int update( String statement , Object parameter)](#int update( String statement , Object parameter))
- [int delete( String statement )](#int delete( String statement ))
- [int delete( String statement , Object parameter)](#int delete( String statement , Object parameter))
- [int commit( )](#int commit( ))
- [void rollback( )](#void rollback( ))
- [void close( )](#void close( ))
- [\<T> T getMapper( Class\<T> type )](#<T> T getMapper( Class<T> type ))
- [Connection getConnection( )](#Connection getConnection( ))
- [使用工具类创建 "SqlSession" / SqlSession工具类](#使用工具类创建 “SqlSession” / SqlSession工具类)
- [二、MyBatis的 "配置文件"](#二、MyBatis的 “配置文件”)
-
- ["映射文件"中的 "主要元素"](#“映射文件”中的 “主要元素”)
- [三、MyBatis的 "映射文件"](#三、MyBatis的 “映射文件”)
-
- ["配置文件"中的 "主要元素"](#“配置文件”中的 “主要元素”)
-
- \<select>元素
- \<insert>元素
- \<update>元素和\<delete>元素
- \<sql>元素
- [\<resultMap>元素 (可解决"属性名" 和 "字段名"不一样导致的数据无法映射成功的问题)](#<resultMap>元素 (可解决“属性名” 和 “字段名”不一样导致的数据无法映射成功的问题))
Mybatis的核心配置 :
一、MyBatis的 "核心对象"
- 在使用MyBatis 框架时,主要涉及 两个核心对象 : SqlSessionFactory 和 SqlSession,它们在MyBatis框架 中起着至关重要 的作用。
1.1 SqlSessionFactory
SqlSessionFactory 是MyBatis 框架中十分重要 的对象,它是单个数据库映射关系 经过编泽后的内存镜像,其主要作用 是 创建SqlSession。
SqlSessionFactory 对象的实例可以通过 SqlSessionFactoryBuilder对象 来构建,而SqlSessionFactoryBuilder 对象 则可以通过 XML配置文件 或一个预先定义好 的 Configuration实例 构建出SqlSessionFactory 的实例。
以下内容 讲解的是 :就是 通过XML配置文件 构建出的SqlSessionFactory实例,其实现代码如下:
javaInputStream inputStream = Resources.getResourceAsStream("配置文件的位置"); //通过SqlSessionFactoryBuilder的 build()方法 + 配置文件来创建 SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory对象 是 线程安全 的,它一旦被创建,在整个应用执行期间都会存在 。如果我们多次地创建同一个数据库的SqlSessionFactory,那么此数据库的资源将很容易被耗尽。为了解决此问题,通常每一个数据库 都会只对应一个 SqlSessionFactory , 所以在 构建SqlSessionFactory实例 时,建议使用单列模式。
1.2 SqlSession :
SqlSession 是MyBatis 框架中另一个重要 的对象 , 它是 应用程序 与 持久层 之间执行与操作的一个单线程对象,其主要作用 是 执行持久化操作。
SqlSession对象 包含数据库 中所有执行SOL操作 的方法 (SqlSession 中有很多操作数据库 的方法 ),由于其底层封装 了JDBC连接 ,所以可以直接使用SqlSession实例 来 执行已映射 的SQL语句
(可用SqlSession 来执行 "映射文件 " 中的sql语句)。
每一个线程都 应该有一个自己的SqlSession实例 ,并且该实例 是不能被共享 的。同时,SqlSession实例 是 线程不安全 的,因此 其使用范围 最好在 一次请求 或一个方法 中,绝不能 将其放在一个类 的静态字段 、实例字段 或 任何类型的管理范围 (如Servlet的HttpSession)中使用。
使用完SqlSession对象 之后,要及时地关闭它 ,通常可以将其放在fnally块中关闭。
java//通过 sqlSessionFactory对象获得"SqlSession" SqlSession sqlSession = sqlSessionFactory.openSession(); try{ //此处执行持久化操作 }finally{ sqlSession.close(); }
SqlSession对象中的操作数据库的方法 :
<T> T selectOne ( String statement )
<T> T selectOne ( String statement ) : 查询方法 : 参数 statement 是在 " 映射文件" 中定义的 <select>元素 的 id 。
目的是 : 获得映射文件 中的 "<select>元素下所代表的 sql语句 作为 selectOne( )方法的参数 ")。使用该方法后,会返回执行SQL语句查询结果 的 一条泛型对象。
<T> T selectOne( String statement , Object parameter )
<T> T selectOne ( String statement , Object parameter ) :查询方法 : 参数 statement 是在 " 映射文件" 中定义的 <select>元素 的 id 。 parameter 是查询所需 的 参数。使用该方法后,会返回执行SQL语句查询结果 的 一条泛型对象。
<E> List<E> selectList ( String statement )
<E> List<E> selectList ( String statement ) : 查询方法 : 参数 statement 是在 "映射文件 " 中定义的 <select>元素 的 id 。使用该方法后,会返回执行SQL语句查询结果 的 泛型对象 的集合。
<E> List<E> selectList ( String statement , Object parameter )
<E> List<E> selectList ( String statement , Object parameter ) : 查询方法 : 参数 statement 是在 " 映射文件 " 中定义的 <select>元素 的 id , parameter 是查询所需的参数 。使用该方法后,会返回 执行SQL语句查询结果的 泛型对象 的集合。
<E> List<E> selectList ( String statement , Object parameter , RowBounds rowBounds )
<E> List<E> selectList ( String statement , Object parameter ) : 查询方法 : 参数==statement ==是在 " 映射文件 " 中定义的 <select>元素 的 id , parameter 是查询所需的参数 ,rowBounds是用于分页 的参数对象 。使用该方法后会返回 执行SQL语句查询结果的 泛型对象 的集合。
void select ( String statement , Object parameter , ResultHandler handler )
void select ( String statement, Object parameter,ResultHandler handler ) : 查询方法 : 参数statement 是在配置文件中定义的 <select>元素 的id,parameter 是查询所需的 参数, ResultHandler对象 用于处理查询返回 的复杂结果集。 (通常用于多表查询)
int insert ( String statement )
int insert ( String statement ) : 插入方法 : 参数 statement 是在 "映射文件 " 中定义的 <select>元素 的 id ,使用该方法后,会返回执行 SQL语句所影响 的行数。
int insert ( String statement , Object parameter )
int insert ( String statement , Object parameter ) : 插入方法 : 参数 statement 是在 " 映射文件 " 中定义的 <select>元素 的 id ,parameter 是查询所需的参数 。使用该方法后,会返回执行 SQL语句所影响 的行数。
int update( String statement )
int update ( String statement ) : 更新方法 : 参数 statement 是在 " 映射文件 " 中定义的 <update>元素 的 id ,使用该方法后,会返回执行 SQL语句所影响 的行数。
int update( String statement , Object parameter)
int update ( String statement , Object parameter ) : 更新方法 : 参数 statement 是在 " 映射文件 " 中定义的 <update>元素 的 id ,parameter 是更新 所需的参数 。使用该方法后,会返回执行 SQL语句所影响 的行数。
int delete( String statement )
int delete ( String statement ) : 删除方法 : 参数 statement 是在 "映射文件 " 中定义的 <delete>元素 的 id ,使用该方法后,会返回执行 SQL语句所影响 的行数。
int delete( String statement , Object parameter)
int delete ( String statement , Object parameter ) : 删除方法 : 参数 statement 是在 " 映射文件 " 中定义的 <delete>元素 的 id ,parameter 是删除 所需的参数 使用该方法后,会返回执行 SQL语句所影响 的行数。
int commit( )
int commit ( ) : 提交事务 的方法。
void rollback( )
int rollback ( ) : 回滚事务 的方法。
void close( )
int close ( ) : 关闭SqlSession 对象。
<T> T getMapper( Class<T> type )
- <T> T getMapper ( Class<T> type ) : 该方法 会返回 Mapper接口 的 代理对象,该对象关联了SqlSession对象 ,开发人员可以使用 该对象直接调用方法操作数据库 。参数type是Mapper的接口类型。MyBatis官方推荐通过
Mapper 对象访问MyBatis。- 该方法 : getMapper( ) 的目的是根据传入的 类类型 :
type
返回一个与该类型匹配的对象。具体实现可能涉及反射机制,用于 创建并返回 一个与传入类类型相匹配 的实例。
Connection getConnection( )
Connection getConnection( ) : 获取 JDBC数据库连接对象 的方法。
使用工具类创建 "SqlSession" / SqlSession工具类
使用工具类 创建 "SqlSession "对象 :
javapackage com.myh.utils; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; /** * 工具类 */ public class SqlSessionUtils { //获得SqlSession的"工具类" private static SqlSessionFactory sqlSessionFactory = null; //初始化 SqlSessionFactory 对象 static { //静态代码块 try { //使用Mybatis提供的Resources类加载mybatis-config.xml配置文件 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); //构建SqlSessionFactory工厂 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } /** * 获得SqlSession对象的静态方法 */ public static SqlSession getSession() { return sqlSessionFactory.openSession(); } }
这样,我们在使用时就 只创建了一个SqlSessionFactory 对象,并且可以通过工具类 的 getSession( ) 方法, 来 获取SqlSession对象。
二、MyBatis的 "配置文件"
MyBatis的核心配置文件 中,包含了很多 影响MyBatis 行为的重要信息 。这些信息通常在一个项目中只会在一个配置文件中编写,并且编写后也不会轻易改动。
"映射文件"中的 "主要元素"
在 MyBatis 框架的 核心配置文件 (即 mybatis-config.xml )中,<configuration> 元素 是配置文件的 根元素,其他元素 都要在 <configuration> 元素内配置。
Mybatis配置文件 中 主要元素图 :(要熟悉 <configuration>元素 各个子元素 的配置。)
ps :
==<Cofgnaion> 的子元素 必须按照图中由上到下 ==的顺序进行配置,否则Mybatis 在解新xml配置文件的时候会报错。
<properties>元素
- <properties> 是一个配置属性 的元素 ,该元素通常用于将内部 的配置 "外在化",即通过外部的配置 来动态地替换内部定义的属性
(直接的使用 : 将外部的 Xxx.properties文件 中的属性 用于 mybatis配置文件 中 )。
例如,数据库的连接等属性,就可以通过典型的 Java属性文件 ( .properties文件 )中的配置 来替换。
ps :
当我们在mybatis 配置文件中 使用 <properties>元素 导入 .properties文件 时,即可在mybatis配置文件 中,即直接使用 .properties文件 中的数据 。
db.properties
propertiesjdbc.driver = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/mybatis jdbc.username = root jdbc.password = root
mybatis-config.xml
xml<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- properties属性 --> <!-- 通过properties属性引入 .properties配置文件, mybatis配置文件中则可直接使用 .properties中的数据,进行"动态替换" --> <properties resource="db.properties"/> <!-- environments属性 --> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- 通过"properties属性"来将 以下的driver、url、username、password 和 .properties配置文件 中的数据进行"动态替换" --> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> </configuration>
完成上述配置后,dataSource 中连接数据库的4个属性 ( driver 、url 、usermame 和password 值将会由db.properties文件 中对应的值 来动态替换。这样就为配置提供了诸多灵活的选择。
除了可以像上述通过外部配置文件 来定义属性值 外,还可以通过配置 <properties>元素 的子元素 <property> ,以及通过方法参数传递 的方式来获取属性值 。由于使用properties配置文件 来配置属性值 可以方便地 在多个配置文件 中使用这些属性值 ,并且方便日后的维护和修改,所以在实际开发中,使用.properties 文件来配置属性值 是最常用的方式。
<settings>元素
<settings>元素 主要用于改变MyBatis运行时 的行为,例如 开启二级缓存 、开启延迟加载 等。
虽然不配置<settings>元素,也可以正常运行MyBatis, 但是熟悉<settings>的配置内容以及它们的作用还是十分必要的。
常见的**<settings>属性配置在 "配置文件" 中的使用** :
xml<settings> <setting name="cacheEnabled" value="true" /> <setting name="lazyLoadingEnabled" value="true" /> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false" /> <setting name="autoMappingBehavior" value="PARTIAL"/> ..... </settings>
<typeAliases>元素
<typeAliases>元素 用于为配置文件 中的Java类型 设置一个简短的名字 ,即 设置别名。别名 的设置与XML配置 相关,其使用的意义 在于减少全限定类名 的冗余。 如 : 可用 <typeAliases>元素 为POJO类 设置一个 "别名"。
xml<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 定义别名 --> <typeAliases> <!-- typeAlias元素 为 typeAliases元素的 "子元素" --> <typeAlias alias="user" type="com.myh.po.Customer"/> </typeAliases> </configuration>
上述示例中,<typeAliases> 元素 的子元素 <typeAlias> 中的type属性 用于指定需要被定义别名 的类的全限定名 ; alias属性 的属性值user 就是自定义的别名 ,它可以代替com.myh.po.Customer使用在MyBatis文件 的任何位置 。如果省略alias属性 ,MyBatis 会默认将类名首字母 小写后 的名称作为别名。
当POJO类过多时,还可以通过自动扫描包 的 形式自定义别名 (此时以类名首字母小写后 的名称为 "别名"),具体示例如下 :
xml<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 定义别名 --> <typeAliases> <!-- 使用自动扫描包来定义"别名" --> <!-- Mybatis会将所用 com.myh.po包中POJO类以首字母小写的名称 作为"别名" --> <!-- 如: Customer 的 默认设置的别名为: customer --> <package name="com.myh.po"/> </typeAliases> </configuration>
需要注意 的是,上述方式的别名只适用于没有使用注解 的情况。如果 在程序中使用了注解 ,则别名 为其注解的值, 具体如下 :
java//使用注解来为该POJO类设置在 mybatis-config.xml配置文件中使用的 "别名" @Alias(value = "customer") public class Customer { ..... }
除了可以使用 <typeAliases>元素自定义别名 外,MyBatis框架还默认 为许多常见的Java类型 (如数值 、 字符串 、日期 和集合 等 )提供了 相应的类型别名 。(可使用时查询常见的Java类型 的别名是什么)
<typeHandler>元素
MyBatis 在 预处理语句( PreparedStatement )中 设置一个参数 或者从结果集 ( ResultSet )中取出一个值 时,都会用其框架内部 注册了的 typeHandler ( 类型处理器 ) 进行相关处理。
typeHandler 的作用 就是将预处理语句 中传入的参数从 javaType ( Java类型) 转换为 jdbcType
( JDBC类型) ,或者从数据库取出结果 时将 jdbcType 转换为 javaType。为了方便转换 ,Mybatis框架提供了一系列默认的类型处理器。
类型处理器 Java 类型 JDBC 类型 BooleanTypeHandler java.lang.Boolean, boolean 数据库兼容的 BOOLEAN ByteTypeHandler java.lang.Byte, byte 数据库兼容的 NUMERIC 或 BYTE ShortTypeHandler java.lang.Short, short 数据库兼容的 NUMERIC 或 SMALLINT IntegerTypeHandler java.lang.Integer, int 数据库兼容的 NUMERIC 或 INTEGER LongTypeHandler java.lang.Long, long 数据库兼容的 NUMERIC 或 BIGINT FloatTypeHandler java.lang.Float, float 数据库兼容的 NUMERIC 或 FLOAT DoubleTypeHandler java.lang.Double, double 数据库兼容的 NUMERIC 或 DOUBLE BigDecimalTypeHandler java.math.BigDecimal 数据库兼容的 NUMERIC 或 DECIMAL StringTypeHandler java.lang.String CHAR, VARCHAR ClobReaderTypeHandler java.io.Reader - ClobTypeHandler java.lang.String CLOB, LONGVARCHAR NStringTypeHandler java.lang.String NVARCHAR, NCHAR NClobTypeHandler java.lang.String NCLOB BlobInputStreamTypeHandler java.io.InputStream - ByteArrayTypeHandler byte[] 数据库兼容的字节流类型 BlobTypeHandler byte[] BLOB, LONGVARBINARY DateTypeHandler java.util.Date TIMESTAMP DateOnlyTypeHandler java.util.Date DATE TimeOnlyTypeHandler java.util.Date TIME SqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP SqlDateTypeHandler java.sql.Date DATE SqlTimeTypeHandler java.sql.Time TIME ObjectTypeHandler Any OTHER 或未指定类型 EnumTypeHandler Enumeration Type VARCHAR 或任何兼容的字符串类型,用来存储枚举的名称(而不是索引序数值) EnumOrdinalTypeHandler Enumeration Type 任何兼容的 NUMERIC 或 DOUBLE 类型,用来存储枚举的序数值(而不是名称)。 SqlxmlTypeHandler java.lang.String SQLXML InstantTypeHandler java.time.Instant TIMESTAMP LocalDateTimeTypeHandler java.time.LocalDateTime TIMESTAMP LocalDateTypeHandler java.time.LocalDate DATE LocalTimeTypeHandler java.time.LocalTime TIME OffsetDateTimeTypeHandler java.time.OffsetDateTime TIMESTAMP OffsetTimeTypeHandler java.time.OffsetTime TIME ZonedDateTimeTypeHandler java.time.ZonedDateTime TIMESTAMP YearTypeHandler java.time.Year INTEGER MonthTypeHandler java.time.Month INTEGER YearMonthTypeHandler java.time.YearMonth VARCHAR 或 LONGVARCHAR JapaneseDateTypeHandler java.time.chrono.JapaneseDate DATE 当MyBatis 框架所提供的 这些类型处理器不能够满足需求时,还可以通过自定义 的方式对类型处理器进行扩展 ( 自定义类型处理器 可以通过实现TypeHandler 接口 或者 继承 BaseTypeHandle类来定义)。
<typeHandler> 元素 就是用于在配置文件 中注册自定义 的类型处理器 的。它的使用方式有两种 :
① 注册一个类 的类型处理器
②注册一个包 中所有 的类型处理器
CustomertypeHandler.java
javapackage com.myh.type; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class CustomertypeHandler implements TypeHandler { @Override public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException { } @Override public Object getResult(ResultSet rs, String columnName) throws SQLException { return null; } @Override public Object getResult(ResultSet rs, int columnIndex) throws SQLException { return null; } @Override public Object getResult(CallableStatement cs, int columnIndex) throws SQLException { return null; } }
mybatis-config.xml
xml<!-- 注册一个类的类型处理器 --> <typeHandlers> <!-- 以单个类的形式配置 --> <typeHandler handler="com.myh.type.CustomertypeHandler"/> </typeHandlers> <!-- 注册一个包中所有类的类型处理器 --> <typeHandlers> <!-- 注册一个包中所有的typeHandler,系统在启动时会自动扫描包下的所有文件 --> <package name="com.myh.type"/> </typeHandlers>
<objectFactory>元素
MyBatis 框架每次创建 结果对象 的新实例 时,都会使用一个对象工厂 ( ObjectFactory )的实例来完成。MyBatis中默认的 ObjectFactory的作用 就是 实例化目标类,它既可以通过++默认构造方法实例化++ ,也可以在参数映射存在的时候通过++参数构造方法来实例化++。
在通常情况下, 我们使用默认的ObjectFactory即可,MyBatis 中默认 的ObjectFactory 是由org.apache.ibatis rflection.factory.DefaultObjectFactory来提供服务的。大部分场景下都不用配置和修改,但如果想覆盖ObjectFactory的默认行为,则可以通过自定义ObjectFactory来实现。
MyObjectFactory.java
javapackage com.myh.objFactory; import org.apache.ibatis.reflection.factory.DefaultObjectFactory; import java.util.List; import java.util.Properties; //自定义工厂类 : 该类可以实现ObjectFactory接口 或 继承 DefaultObjectFactory类 public class MyObjectFactory extends DefaultObjectFactory { //要继承DefaultObjectFactory类 private static final long serialVerSionUID = -4114845625429965832L; @Override public <T> T create(Class<T> type) { return super.create(type); } @Override public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { return super.create(type, constructorArgTypes, constructorArgs); } @Override public void setProperties(Properties properties) { super.setProperties(properties); } @Override public <T> boolean isCollection(Class<T> type) { return super.isCollection(type); } }
mybatis-config.xml
xml<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <objectFactory type="com.myh.objFactory.MyObjectFactory"> <property name="name" value="MyObjectFactory"/> </objectFactory> </configuration>
<plugins>元素
- MyBatis 允许在已映射语句执行过程中 的某一点 进行拦截调用 ,这种拦截调用 是通过插件 来实现的。<plugins> 元素 的作用 就是配置用户所开发 的插件。如果用户想要进行插件开发 ,必须要先了解其内部运行原理,因为在试图修改或重写已有方法的行为时,很可能会破坏MyBatis原 有的核心模块。
<environments>元素
在配置文件 中,<environments>元素 用于对环境 进行配置。MyBatis 的 环境配置 实际上就是 数据源的配置,我们可以通过 <environments>元素 配置多种数据源 ,即配置多种数据库。
xml<!-- environments属性 --> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- 通过"properties属性"来将 以下的driver、url、username、password 和 .properties配置文件 中的数据进行"动态替换" --> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments>
在上述代码中,<environments>元素 是环境配置 的 根元素,它包含个一default属性 ,该属性用于指定默认 的环境ID 。 是 <environments>元素的 "子元素",它 : <environment> 可以定义多个,其记属性用于表示所定义环境的ID值 。在 environment元素内,包含事务管理 ( transactionManager ) 和 数据源 ( dataSource ) 的配置信息 ,其 <transactionManager>元素 用于配置事务管理 ,它的type 属性用于指定事务管理 的方式,即使用哪种事务管理器 ;<dalaSource>元素 用于配置数据源 ,它的type属性 用于指定使用哪种数据源。
在MyBatis中,可以配置两种 类型的事务管理器,分别是 JDBC 和 MANAGED 。JDBC : 此配置直接使用了JDBC 的提交 和回滚设置 ,它依赖于从数据源 得到的连接来管理事务 的作用域 。
MANAGED : 此配置从来不提交 或回滚 一个连接 ,而是让容器来管理事务 的整个生命周期 。在默认情况 下,它会关闭连接 ,但一些容器并不希望这样,为此可以将closeConnection属性 设
置为false 来阻止它默认 的关闭行为。
ps :
如果没有必要中 使用的是 Spring+ MyBatis,则 没有必要 在MyBatis ( mybatis-config.xml ) 中 配置事务管理器,因为实际开发中 ,会使用Spring 自带的管理器 来实现事务管理。
<mappers>元素
在配置文件 ( mybatis-config.xml )中,<mappers>元素 用于 指定MyBatis 映射文件 (引入"映射文件 ")(XxxMapper.xml )的 位置,一般可以使用以下 4种方法 引入映射文件 。 ( 一个mybatis-config.xml 配置文件 可以引入多个"映射文件"。)
① 使用 "类路径" 引入
② 使用 "本地文件路径" 引入
③ 使用 "接口类" 引入
④ 使用 "包名" 引入① 使用 "类路径" 引入
xml<mappers> <!-- 使用"类路径"读取"映射文件" --> <mapper resource="com/myh/mapper/CustomerMapper.xml"/> </mappers>
② 使用 "本地文件路径" 引入
xml<mappers> <!-- 使用"本地文件路径"引入"映射文件" --> <mapper url="file:///D:/com/myh/mapper/CustomerMapper.xml"/> </mappers>
③ 使用 "接口类" 引入
xml<mappers> <!-- 使用"接口类"引入"映射文件" --> <mapper class="com.myh.mapper.CustomerMapper"/> </mappers>
④ 使用 "包名" 引入
xml<mappers> <!-- 使用"包名"引入"映射文件" --> <package name="com.myh.mapper"/> </mappers>
三、MyBatis的 "映射文件"
- 映射文件 ( XxxMapper.xml )是Mybatis 框架中十分重要的文件,可以说,Mybatis框架的强大之处 就体现在"映射文件"的编写上。
- 在映射文件 中,<mapper>元素 是映射文件 的根元素 ,其他元素都是它的子元素 。
"配置文件"中的 "主要元素"
<select>元素
<select>元素 用于映射 "查询语句 ",它可以帮助我们从数据库中读出数据,并组装数据给企业开发者。
xml<!-- "查询数据"--> <select id="findCustomerById" parameterType="Integer" resultType="com.myh.po.Customer"> select * from t_customer where id = #{id} </select>
上述语句中的唯一标识为 findCustomerByld,它接收 一个 Integer 类型 的参数 ,并返回 一个Customer类型 的对象。
<select>元素 中,除了 上述代码中的几个属性外,还有其他一些可以配置 的属性,如下所示 :
属性 说明 id 表示命名空间中 的唯一标识符 , 常与命名空间组合起来使用 。组合后如果不唯一, MyBatis会抛出异常。 parameterType 该属性表示传入SQL语句 的参数类 的全限定名 或者别名 。它是一个可选属性, 因为MyBatis 可以通过TypeHandler 推断出具体传入语句 的参数 。其默认值是unset (依赖于驱动)。 resultType 从SQL语句中返回的类型 的类 的全限定名 或者别名 。如果是集合类型 ,那么返回的应该是集合可以包含 的类型 ,而不是集合本身 。返回时可以使用resultType 或resultMap之一。 resultMap 表示外部resultMap 的命名引用 。返回时可以使用resultType 或resultMap之一。 flushCache 表示在调用SQL语句 之后,是否需要MyBatis清空之前查询 的本地缓存 和二级缓存 。其值为布尔类型( truelfalse),默认值为false 。如果设置为true ,则任何时候只要SQL语句被调用,都会清空本地缓存 和二级缓存。 useCache 用于控制二级缓存 的开启 和关闭 。其值为布尔类型( truelfalse),默认值为true ,表示将查询结果 存入二级缓存中。 timeout 用于设置超时参数 ,单位为秒 。超时将抛出异常。 fetchSize 获取记录 的总条数设定 ,其默认值是unset (依赖于驱动)。 statementType 用于设置MyBatis 使用哪个JDBC 的Statement 工作,其值为STATEMENT 、PREPARED(默认值) 或CALLABLE , 分别对应JDBC中的Statement 、PreparedStatement 和 CallableStatement。
属性 说明 resultSetType 表示结果集 的类型 ,其值可设置为FORWARD_ONLY、SCROLL_SENSITIVE 或SCROLL_INSENSITIVE, 它的默认值是unset (依赖于驱动)。
<insert>元素
- <insert>元素 用于映射"插入语句",在执行完 元素中定义的SQL语句 后,会返回 一个表示插入记录数 的整数。
xml<!-- useGeneratedKeys="true" : 获得该insert语句插入数据库时形成的"主键id" / 获得数据库内部产生的主键id keyProperty="id" : 将插入或更新时的"返回值"赋值到PO类的对应的"属性"上 : 即将刚获得的"主键id"赋值到PO类对应的id属性上 --> <!-- 该insert语句的返回值 : ①返回插入成功的行数 ②插入行的主键id --> <insert id="addCustomer" parameterType="com.myh.po.Customer" flushCache="true" statementType="PREPARED" keyProperty="id" keyColumn="" useGeneratedKeys="true" timeout="20"> insert into t_customer(username,jobs,phone) values(#{username},#{jobs},#{phone}) </insert>
以上的 insert语句 的返回值 : ①返回插入成功的行数 ②插入行的主键id 。
从上述代码 中可以看出,<insert>元素 的属性 与 <select>元素 的 属性大部分相同,<insert>元素 包含了 3个特有属性。
- <insert>元素 中的三个特有 属性 :
属性 说明 keyProperty ( 仅对insert和update有用 )此属性 ( keyProperty )的作用 是将插入 或 更新操作时 的返回值赋值给 PO类 的某个属性,通常会设置为"主键 "对应的属性。 (通常会设置该属性的值 为"id" (即将插入形成的"主键id "值赋值到PO类 中 )。如果需要设置联合主键 ,可以在多个值 之间用逗号隔开 。 例子如 : keyProperty ="i'd" ( 要结合useGeneratedKeys 属性使用 ) : 将useGeneratedKeys 属性获得的 ( 插入形成的 ) "主键id " 赋值到PO类 的对应的id属性 上,这样就能获得insert语句 生成的数据对应 的"主键id"了。 keyColumn ( 仅对insert 和update 有用 ) 此属性用于 设置第几列 是主键,当主键列不是表中 的第一列时需要设置,在需要主键联合 时,值可以使用逗号隔开。 useGeneratedKeys ( 仅对insert 和update 有用 )此属性会使 MyBatis 使用 JDBC 的 getGeneratedKeys( ) 方法来获取由数据库内部生产 的 主键 (此时一般配合keyProperty 属性使用来将该"主键 赋值给PO类 对应的属性 上。"), 如MySQL 和SQL Server 等自动递增 的字段 ,其 默认值 为false。 执行插入操作 后,很多时候我们会需要返回插入成功 的数据生成 的主键值 ( 表中主键id ),此时就可以通过
上面所讲解的3个属性来实现。
- 如果使用的数据库支持主键自动增长 (如MySQL ),那么可以通过keyProperty属性 指定PO类 的某个属性接收主键返回值 ( 通常会设置到id属性上 : 将主键id 赋值给PO类 的 id属性 上 ),同时还要通过 useGeneratedKeys 属性才能实现目标功能。 例子如下 :
<insert>元素 中的三个特有 属性 例子如 :
CustomerMapper.xml (映射文件) :
xml<!-- useGeneratedKeys="true" : 获得该insert语句插入数据库时形成的"主键id" / 获得数据库内部产生的主键id keyProperty="id" : 将插入或更新时的"返回值"赋值到PO类的对应的"属性"上 : 即将刚获得的"主键id"赋值到PO类对应的id属性上 --> <!-- 该insert语句的返回值 : ①返回插入成功的行数 ②插入行的主键id --> <insert id="addCustomer" parameterType="com.myh.po.Customer" keyProperty="id" useGeneratedKeys="true" > insert into t_customer(username,jobs,phone) values(#{username},#{jobs},#{phone}) </insert>
以上的 insert语句 的返回值 : ①返回插入成功的行数 ②插入行的主键id。
CustomerTest.java (测试类) :
javapublic class CustomerTest { @org.junit.Test //单元测试 public void addCustomerTest() throws IOException { //1.读取mybatis框架的配置文件 String resource = "com/myh/映射文件的元素/mybatis-config.xml"; //通过"输入流"读取mybatis配置文件 /* 在该mybatis-config.xml配置文件中,已配置了"数据源"信息 和配置了"映射文件 : XxxMapper.xml"的位置, 可实施加载"映射文件" */ InputStream inputStream = Resources.getResourceAsStream(resource); //2.根据配置文件"构建会话工厂 : SqlSessionFactory " SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.通过SqlSessionFactory(会话工厂)创建SqlSession("会话"对象) SqlSession sqlSession = sqlSessionFactory.openSession(); Customer customer = new Customer(); customer.setUsername("小蓝"); customer.setJobs("学生"); customer.setPhone("12345678"); //将该Customer对象存入到数据库中,同时目的是: 将存入到数据库中的数据对应的"主键id"获得且返回 int insert = sqlSession.insert("CustomerMapper.addCustomer", customer); /** * 输出"插入数据"形成的"主键id值" (从数据库中获得的主键id值是存储在Customer这个PO类中的) */ System.out.println(customer.getId()); if (insert > 0) { System.out.println("你成功插入了" + insert + "条数据!"); } else { System.out.println("插入数据操作失败! "); } //4.设置"事务管理" sqlSession.commit(); //5.关闭SqlSession sqlSession.close(); } }
通过上述的<insert>元素 的三个特有属性 ,即可获得插入数据 的对应 的 " 主键id"。
如果使用的数据库不支持主键自动增长 (如Oracle ), 或者支持增长的数据库 取消了主键自增 的规则时,也可以使用MyBatis 提供的另一种方式 来自定义生成主键 。 例子如下 :
xml<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- 映射文件中,插入数据用 <insert>元素 --> <!-- #{} : 相当于"占位符" ${} : 相当于在sql语句后要拼接的"字符串" --> <mapper namespace="CustomerMapper"> <insert id="insertCustomer" parameterType="com.myh.po.Customer"> <selectKey keyProperty="id" resultType="Integer" order="BEFORE"> select if(max(id) is null,1,max(id) + 1)as newId from t_customer </selectKey> insert into t_customer(username,jobs,phone) values(#{username},#{jobs},#{phone}) </insert> </mapper>
上述代码中,<selectKey> 元素会首先运行 ,它会通过自定义的语句 来设置数据 中的主键 (如果
t_customer表中没有记录 ,则将id设置为1 ,否则就将id的最大值加1 ,来为新的主键),然后再调用插入语句 。
<selectKey>元素 在使用时可以设置以下几种属性 :
xml<selectKey keyProperty="id" resultType="Integer" order="BEFORE" statementType="PREPARED">
在上述 <selectKey>元素 的几个属性中,keyProperty 、 resultType 和statementType 的作用与前面讲解的相同,order 属性 可以被设置为BEFORE 或AFTER 。如果设置 为BEFORE,那么它会首先执行 <selectKey>元素 中的配置 来设置主键 ,然后执行插入语句 ;如果设置为AFTER ,那么它会先执行插入语句 ,然后执行 <selectKey>元素中的配置内容。
<update>元素和<delete>元素
- <update> 和 <delete>元素 的使用比较简单,它们的属性配置也基本相同 ,其常用属性如下 :
xml<!-- 更新 --> <update id="updateCustomer" parameterType="com.myh.po.Customer" flushCache="true" statementType="PREPARED" timeout="20"> </update> <!-- 删除 --> <delete id="deleteCustomer" parameterType="com.myh.po.Customer" flushCache="true" statementType="PREPARED" timeout="20"> </delete>
从上述配置代码中可以看出,<update>和<delete>元素 的属性 基本与 <select>元素中 的属性一致 。
与 <insert>元素 一样,<update> 和<delete>元素在执行完之后 ,也会返回一个表示影响记录条数 的整数,其使用示例如下 :
xml<!-- 更新 --> <update id="updateCustomer" parameterType="com.myh.po.Customer"> update t_customer set username = #{username},jobs=#{jobs},phone=#{phone} where id = #{id} </update> <!-- 删除 --> <delete id="deleteCustomer" parameterType="Integer"> delete from t_customer where id = #{id} </delete>
<sql>元素
在一个映射文件 中,通常需要定义多条SQL语句 ,这些SQL语句的组成 可能有一部分是相同的 ( 如多条select语句 中都查询相同的id 、username 、 jobs 字段 ),如果每一个SQL语句都重写遍相同的部分 , 势必会增加代码量,导致映射文件过于臃肿。
那么有没有什么办法将这些SQL语句 中相同 的组成部分抽取出来,然后在需要的地方引用呢 ?
答案是肯定的,我们可以在映射文件 中使用MyBatis 所提供的 <sql>元素 来解决上述问题。<sql>元素的作用 : 就是定义可重用 的SQL代码片段,然后在其他语句中引用 这一代码片段。
例子如 :
xml<sql id="customerColumns"> id,username,jobs,phone</sql> <select id="findCustomerById" parameterType="Integer" resultType="com.myh.po.Customer"> select <include refid="customerColumns"/> from t_customer where id = #{id} </select>
<resultMap>元素 (可解决"属性名" 和 "字段名"不一样导致的数据无法映射成功的问题)
<resultMap>元素 表示结果映射集,是 MyBatis 中最重要 也是 最强大 的元素。它的主要作用 : 是
定义映射规则、级联的更新 以及 定义类型转化器 等。ps :
<resultMap>元素 可解决"属性名 " 和 "字段名 " 不一样导致 的数据无法映射成功 的问题。<resutMap>元素 中包含了属性 / 子元素,如下所示 :
xml<!-- resultMap的元素结构 --> <resultMap type="" id=""> <constructor> <!-- 类在实例时,用来注入"结果"到"结构方法"中 --> <idArg/> <!-- ID参数;标记结果为ID --> <arg/> <!-- 注入到构造方法的一个普通结果 --> </constructor> <id/> <!-- 用于表示哪个"列"是"主键" --> <result/> <!-- 注入到"字段"或"JavaBean属性"的普通结果 --> <association property=""/> <!-- 用于一对一关联 --> <collection property=""/> <!-- 用于一对多关联 --> <discriminator javaType=""> <!-- 使用"结果值"来决定哪个"结果映射"--> <case value=""></case> </discriminator> </resultMap>
<resutMap>元素 的 属性 关系如下表所示 :
属性 描述 type 表示需要 映射 的POJO ( 普通Java对象 ) id 这个 resultMap 的 唯一标识。 <resutMap>元素 的 子元素 关系如下表所示 :
子元素 描述 <constructor> 用于配置构造方法 ( 当一个POJO 中未定义无参 的构造方法 时,就可以使用 <constructor>元素 进行配置)。 <id> 分别标记 POJO中属性 中的"主键 "和 标记数据库表中字段 的 "主键",并 将二者进行关联。 ps : 这意味着,通过 <resultMap> 中的 <id>元素 的配置,POJO 中 "主键"属性名 不用 和数据库中 "主键"名相同。 <result> 表示 POJO 中 "属性 "和 数据库表中列 的 映射关系。(用于将 POJO 中 "属性 "和 数据库表 中的 "列 "进行关联。 ) ps : 这意味着,通过 <resultMap> 中的 <result>元素 的配置,数据库 中的 "字段 " 以及 该"字段 "相对应的 "属性 "名,不用一致。(在 <result>中设置各自的名称即可) <association> 表示"一对一"关联。用于处理"多表 "时的关联关系。 <collection> 表示"一对多"关联。用于处理"多表 "时的关联关系。 <discriminator> 使用"结果值 "来决定 哪个"结果映射"。用于处理 一个单独的数据库查询 返回很多不同数据类型 结果集 的情况。 在默认情况下,MyBatis 程序在运行时会 自动地将查询到 的数据 与需要返回的对象 的属性 进行匹配赋值 ( 需要表中的 列名 与对象的属性名称完全一致 )。 然而实际开发时,数据表中的列 和需要返回的对象的属性 可能不会完全一致, 这种情况下 MyBatis是不会自动赋值的。此时,就可以使用 <resultMap>元素进行处理。
实际开发中,如果当POJO中"属性名 " 和 数据库中"字段名 " 不一致,此时查询数据库,数据会无法映射到POJO类中,最后导致查询到的内容为 : null 。 此时用 <resultMap>元素即可解决这个问题。
例子如 :
此时可使用"映射文件 " 中的因属性名 和 字段名不一致 而导致的数据无法映射 到POJO 中的问题。如下所示 :
UserMapper.xml
xml<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="UserMapper"> <!-- select元素中使用resultType时,当数据库中"字段名" 和POJO中"属性名"不一致时,select的数据将则无法映射到POJO类中,即输出内容为null --> <!-- select元素中用resultMap时,数据库中"字段名" 和 POJO中"属性名"不用保持一致,此时也能完成将select到的数据映射到POJO类中--> <select id="selectUser_resultType" resultType="com.myh.po.User" parameterType="Integer"> select * from t_user where t_id = #{id} </select> <!-- 上面这个select的查询的数据是无法映射到POJO类中,即select的数据为null,因为数据库中"字段名" 和 POJO中的"属性名", 此时可用 <resultMap>元素来解决这个问题 --> <resultMap id="resultMap" type="com.myh.po.User"> <!-- 下面配置的目的 : "属性名" 和 "字段名" 可以不用保持一致 --> <id property="id" column="t_id"/> <result property="name" column="t_name"/> <result property="age" column="t_age"/> </resultMap> <!-- 因为此处用了resultMap(已经配置好了,完成各种内容的"映射了",所以即使"属性名" 和 "字段名"不一致,也能select到数据) --> <select id="selectUser_resultMap" resultMap="resultMap" parameterType="Integer"> select * from t_user where t_id = #{id} </select> </mapper>
UserTest.java (测试类)
javapublic class UserTest { @org.junit.Test //单元测试 public void selectUser_resultType_resultMap_Test() throws IOException { //1.读取mybatis框架的配置文件 String resource = "com/myh/映射文件的元素/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); //2.根据配置文件"构建会话工厂 : SqlSessionFactory " SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.通过SqlSessionFactory(会话工厂)创建SqlSession("会话"对象) SqlSession sqlSession = sqlSessionFactory.openSession(); User user1 = (User)sqlSession.selectOne("UserMapper.selectUser_resultType", 2); /** 此处输出的内容为 : null ,因为字段名和属性名 不一样,数据无法映射成功,最后输出的内容为 : null */ System.out.println("从数据库中查询到的数据为(通过resultType获得): "+user1); /** 此处输出的内容为 : "查询到的数据",即使"属性名" 和 "字段名"没有保持一致,但通过resultMap元素的配置,查询到的数据依然能 映射到POJO类中。 */ User user2 = (User)sqlSession.selectOne("UserMapper.selectUser_resultMap", 2); System.out.println("从数据库中查询到的数据为(通过resultMap获得): "+user2); //4.关闭SqlSession sqlSession.close(); } }
控制台输出结果为 :