项目
博客
归档
资源链接
关于我
项目
博客
归档
资源链接
关于我
Mybtais核心参考文档资源
2025-07-26
·
·
原创
·
mybatis
·
本文共 3,341个字,预计阅读需要 12分钟。
技术点: 1. SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession的实现原理 2. mybatis的一级二级缓存、延迟加载、分页插件、关联查询、动态sql、核心配置(settings/properties...) ## 二、Mybatis Dao开发 使用Mybatis开发Dao,通常有两个方式:原始Dao开发方式和Mapper代理开发方式。 ### 2.1 Mybatis API #### SqlSessionFactoryBuilder: SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,所以可以将SqlSessionFactoryBuilder当成一个工具使用,最佳便用范围是方法范围即方法体内局部变量。 #### SqlSessionFactory: SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqISessionFactory。 openSession(布尔类型),true为自动提交事务,false则相反。 #### SqlSession: SqlSession是一个面向用户(程序员)的接口,其中提供了很多操作数据库的方法。如:selectOne(返回单个对象)、selectList(返回单个或多个对象)、insert、update、delete。 SqISession的实例不能共享使用,它是线程不安全的,每个线程都应该有它自己的SqISession实例,因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。 ### 2.2 Mybatis工具类 为了简化MyBatis的开发,可将MyBatis进一步封装 ```java 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 /** *Mybatis工具类 */ public class MybatisUtil { /**不让用户在外界创建工具类对象*/ private Mybatisutil(){} /**初始化sqlSessionFactory对象*/ private static SqlSessionFactory factory; static { try { InputStream in=Resources.getResourceAsStream("mybatis-config.xm1"); factory= new Sq1SessionFactoryBuilder().build(in); }catch(IoException e) { e.printStackTrace(): } } /**获取sq1Session对象的方法*/ public static SqlSession getSession(){ return factory.openSession(true); //true自动提交,相当于sq1Session.commit() } } ``` ### 2.3 原始DAO开发方式 原始Dao开发方法需要程序员编写Dao接口和Dao实现类,无非就是Dao实现类里面调用映射文件里面定义的sql而已。 实体类 ```java //Dept实体类 public class Dept { private Integer deptno; private String dname; private String loc } ``` 原始Dao开发方式:程序员编写Dao接口和Dao实现类 1、编写Dept实体类 2、编写DeptDao接口,增删改查规范:【com.xx.dao】 - int insert(Dept dept); - int delete(Integer deptno); - int update(Dept dept); - `List
select(`); - Dept selectById(Integer deptno); 3、编写DeptDaoImpl类,实现DeptDao接口,重写接口里面的抽象方法【com.xx.dao.impl】 - 3.1通过MybatisUtil调用getSession()得到SqlSession对象; - 3.2通过SqlSession对象调用sQL映射文件中的sQL; - 3.3 关闭sqlSession: 4、编写DeptDao.xml映射文件 ```java public class DeptDaoImpl implements DeptDao { @Override publicint insert(Dept dept){ SqlSession session =MybatisUtil.getSession(); int num = session.insert(s:"dept.insert",dept); session.close(); return num; } @Override public int delete(Integer deptno){ SqlSession session = MybatisUtil.getSession(); int num=session.delete(s:"dept.delete",deptno); session.close(); return 0; } } ``` mapper文件 ```xml
select deptno,dname,1oc from dept where deptno=#[deptno}
insert into dept(dname,loc)values(#{dname},#{1oc})
update dept set dname=#{dname},1oc=#{1oc} where deptno=#{deptno}
delete from dept where deptno=#{deptno]
``` 加载mapper文件: ```xml
``` ### 2.4 Mapper代理方式(重点) Mapper代理开发方式只需要程序员编写Mapper接口(相当于Dao接口),由MyBatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。 序员编写Mapper接口需要遵循一些开发规范,MyBatis可以自动生成Mapper接口实现类代理对象。 开发规范 1、Mapper.xml文件中的namespace与mapper接口的类路径相同。 2、Mapper.xml中定义的每个标签的id与Mapper接口方法名相同。 3、Mapper.xml中定义的每个sql的parameterType的类型与Mapper接口方法的参数类型相同。 4、Mapper.xml中定义的每个sql的resultType的类型与Mapper接口方法返回值类型相同。 注:Mapper.xml映射文件最好和Mapper接口名称一致。 - 批量查询:方法返回值为List类型,表示SqISession对象将调用selectList)方法。 - 单条查询:方法返回值为单个实体对象,表示SqISession对象将调用selectOne(方法。 - 增别改: - 方法返回值为void,表示SqlSession对象中insert,update,delete方法的返回值不做任何处理。 - 方法返回值为int类型,表示SqISession对象中insert,update,delete方法的返回值直接返回。 - 方法返回值为boolean类型,表示根据SqlSession对象中的insert,update,delete方法返回值(影响数据库的条数)判断操作是否成功,如果影响数据库的条数大于0条,表示成功,否则表示失败。 ## 三、Mybatis核心配置文件 ### 3.1 properties属性 将数据库连接参数单独配置在db.properties中,只需要在mybatis-config.xml中加载db.properties的属性值。在mybatis-config.xml中就不需要对数据库连接参数硬编码。 ```properties jdbc.mysql.driver=com.mysql.cj.jdbc.Driver jdbc.mysq1.ur1=jdbc:mysql://1ocalhost:3306/ssmcharacterEncoding=utf8&useSSL=false&serverTimezone=UTc&rewriteBatchedStatements=true jdbc.mysql.username=root jdbc.mysq1.password=root ``` 使用`
`标签加载属性文件: - resource:从classpath下读取资源文件。 - classpath为maven项目中的src/main/resources目录+src/main/java目录,编译之后的目录为target/classes; - url:从当前系统环境的文件系统中读取资源。 - windows: d:/conf/test.properties - linux:/home/tom/conf/test.properties ```properties
``` 在环境中使用: ```xml
``` 建议:在properties文件中定义属性名要有一定的特殊性,如:XxxxX.Xxxxx.Xxxx; ### 3.2 settings全局配置参数 MyBatis框架在运行时可以调整一些运行参数,比如:开启二级缓存、开启延迟加载 | 参数名 | 一句话说明 | 有效值 | 默认值 | | ------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------------------- | | **cacheEnabled** | 是否开启二级缓存(mapper 级别)。 | true / false | **true** | | **lazyLoadingEnabled** | 是否允许延迟加载关联对象。 | true / false | **false** | | **aggressiveLazyLoading** | true:任何方法触发即加载全部延迟属性;false:按需加载。 | true / false | **false**(≤3.4.1 为 true) | | **multipleResultSetsEnabled** | 是否允许一条语句返回多结果集(已弃用,无实际作用)。 | true / false | **true** | | **useColumnLabel** | 用列别名还是列名作为结果集 key。 | true / false | **true** | | **useGeneratedKeys** | 是否允许 JDBC 自动生成主键。 | true / false | **false** | | **autoMappingBehavior** | 自动映射策略。 | NONE / PARTIAL / FULL | **PARTIAL** | | **autoMappingUnknownColumnBehavior** | 遇到未知列时的处理。 | NONE / WARNING / FAILING | **NONE** | | **defaultExecutorType** | 默认执行器。 | SIMPLE / REUSE / BATCH | **SIMPLE** | | **defaultStatementTimeout** | 数据库响应超时时间(秒)。 | 任意正整数 | **未设置(null)** | | **defaultFetchSize** | JDBC fetchSize 提示值。 | 任意正整数 | **未设置(null)** | | **safeRowBoundsEnabled** | 是否允许在嵌套语句中使用 RowBounds。 | true / false | **false** | | **safeResultHandlerEnabled** | 是否允许在嵌套语句中使用 ResultHandler。 | true / false | **true** | | **mapUnderscoreToCamelCase** | 开启下划线转驼峰自动映射。 | true / false | **false** | | **localCacheScope** | 一级缓存作用范围。 | SESSION / STATEMENT | **SESSION** | | **jdbcTypeForNull** | 当参数为 null 时,默认的 JDBC Type。 | NULL、VARCHAR、OTHER … | **OTHER** | | **lazyLoadTriggerMethods** | 可以触发延迟加载的方法名列表。 | 逗号分隔的方法名 | **equals,clone,hashCode,toString** | | **callSettersOnNulls** | 结果集中值为 null 时是否仍调用 setter。 | true / false | **false** | | **returnInstanceForEmptyRow** | 全列均为 NULL 时返回空实例还是 null。 | true / false | **false** | | **logPrefix** | 日志名前缀。 | 任意字符串 | **未设置** | | **logImpl** | 指定日志实现。 | SLF4J / LOG4J / LOG4J2 / JDK\_LOGGING / COMMONS\_LOGGING / STDOUT\_LOGGING / NO\_LOGGING | **未设置(自动探测)** | | **proxyFactory** | 延迟加载代理工厂。 | CGLIB(已弃用) / JAVASSIST | **JAVASSIST** | | **vfsImpl** | 自定义 VFS 实现类,多个可用逗号分隔。 | 类的全限定名 | **未设置** | | **useActualParamName** | 允许在 SQL 中使用方法形参名(需编译加 `-parameters`)。 | true / false | **true** | | **configurationFactory** | 提供 `Configuration` 实例的工厂类,必须含 `static Configuration getConfiguration()` 方法。 | 类的全限定名 | **未设置** | **mybatis-config.xml** 全局配置文件 ```xml
``` ### 3.3 typeAliases类型别名 在mapper.xml中,定义很多的statement。statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。 | 别名 | 映射的类型 | | ----------- | --------------------- | | `_byte` | `byte` | | `byte` | `java.lang.Byte` | | `short` | `short` | | `short` | `java.lang.Short` | | `_int` | `int` | | `int` | `java.lang.Integer` | | `_integer` | `int` | | `integer` | `java.lang.Integer` | | `_long` | `long` | | `long` | `java.lang.Long` | | `_float` | `float` | | `float` | `java.lang.Float` | | `double` | `double` | | `double` | `java.lang.Double` | | `_boolean` | `boolean` | | `boolean` | `java.lang.Boolean` | | `string` | `java.lang.String` | | `date` | `java.util.Date` | | `map` | `java.util.Map` | | `hashmap` | `java.util.HashMap` | | `list` | `java.util.List` | | `arraylist` | `java.util.ArrayList` | | `object` | `java.lang.Object` | #### MyBatis默认支持别名 ##### 自定义别名 **单个类型的别名配置:typeAlias** - type:类型,java中类的全限定名。 - alias: 别名。 ```xml
``` **批量类型别名的配置:package**。 - name:需要配置别名的类所在的包。 - 设置包名之后,此包下所有的类都拥有类型别名,其别名为:该类的类名,首字母大小均可。 ```xml
``` **注解定义别名**: 在实体类上可以使用@Alias("name")注解来标识该类的别名。 ```java @Alias("depart") public class Dept { } ``` 注意:配置和注解仅能使用一种方式,当注解存在时,则其别名为其注解值 ### 3.4 mappers映射器 mappers:映射器,加载mapper文件。 #### 单个加载映射文件 单个映射文件的加载:mapper。 resource:从classpath下加载mapper文件。 ```xml
``` class:配置dao接口的全限定名,通过Java中的dao接口的名称加载mapper.xml文件。 ```xml
``` 要求: 1. 必须使用mapper代理的开发方式; 2. mapper.xml文件的名称必须与dao接口的名称保持一致; 3. mapper.xml文件必须与dao接口放在同一个目录下; 注意:同一个目录是指编译之后的目录,并非开发时的目录 #### 批量加载映射文件 批量映射文件的加载:package - **name:mapper接口与mapper文件存放的共同的目录名称**。 此种配置使mapper扫描指定包,并在此包下获取所有的接口以及与接口名称相同mapper文件,并加载; ```xml
``` 要求:与mapper接口加载单个映射文件(class方式)一致。 ### 3.5 Mybatis配置文件的标签顺序 Mybatis配置文件中各标签的位置顺序如下: ```xml properties?, settings?, typeAliases?, typeHandlers?, objectFactory? objectwrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers? 具体可以参考http://mybatis.org/dtd/mybatis-3-config.dtd文件。 ``` ## 输入映射 ### 4.1 parameterType输入映射 parameterType:配置输入参数的类型。 #### 简单类型 Java基本数据类型以及包装类,String类型。`parameterType="java.lang.Integer"` #### 实体类或自定义类型 开发中通过实体类传递查询条件,查询条件是综合的查询条件,不仅包括实体类中查询条件还包括其它的查询条件,这时可以使用包装对象传递输入参数。`parameterType="com.hualan.entity.Users"` // " #### Map类型 `parameterType="hashmap"`, `parameterType="java.util.HashMap"`, 对应上面的typeAliases类型别名表 mybatisSQL语句的占位符是 #{参数名} - 如果参数是简单类型(基本数据类型/包装类/String类型),#{任意名称} - 如果参数是实体类类型,#{属性名} - 如果参数是map类型,#{key} ## 输出映射 ### 4.2 resultType输出映射 简单类型 查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射。 resultType输出映射:配置输出结果的类型 - 简单类型:基本数据类型、包装类、String - 实体类类型 - HashMap:key-字段名称,value为值,如果是多行数据:List
实体类属性名和查询结果集的列名不一致: - 方式一:开启下划线转驼峰:userName->user_name - 方式二:定义列别名;userName->uname - 方式三:resultMap手动映射; resultMap resultType可以指定将查询结果映射为实体类,但需要实体类的属性名和SQL查询的列名一致方可映射成功,当然如果开启下划线转驼峰或Sql设置列别名,也可以自动映射。 - 如果SQL查询字段名和实体类的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系,resultMap实质上还会将查询结果映射到实体类对象中。 - resultMap可以实现将查询结果映射为复合型的实体类,比如在查询结果映射对象中包括实体类和list实现一对一查询和一对多查询。 - resultType: 自动映射。 - resultMap:手动映射。 - id: 唯一标识,名称; - type: 手动映射的java类型; - 子标签
配置数据库表中的主键和实体类中属性的对应关系 - 子标签
配置数据库表中的普通字段和实体类中属性的对应关系; - property:实体类中的成员变量名: - column:结果集中的字段名称; - javaType:实体类成员变量的类型,由mybaits自动识别,可不配置; - jdbcType:表字段的类型,由mybaits自动识别,可不配置; - typeHandler: 自定义类型处理器,用的相对较少 ## 动态SQL ### 什么是动态SQL 动态Sq是指MyBatis对Sql语句进行灵活操作,通过表达式进行判断,对Sql进行灵活拼接、组装。 比如: - 我们要查询姓名中带M和高于1000的员工信息; - 可能有时候我们需要不带条件查询; - 可能有时候我们需要模糊查询; - 可能有时候需要根据多条件查询; - 动态SQL可以帮助我们解决这些问题。 通过Mybatis提供的各种标签方法实现动态拼接sql。 **动态 SQL 标签**一共只有 **9 个**,可分成 3 组记忆: 1. 条件判断组:`if`、`choose / when / otherwise` 2. 裁剪拼接组:`where`、`set`、`trim` 3. 循环与辅助组:`foreach`、`bind`、`sql / include` ```xml
SELECT * FROM blog WHERE state = 'ACTIVE'
AND title LIKE #{title}
SELECT * FROM blog WHERE state = 'ACTIVE'
AND title LIKE #{title}
AND author_name = #{author.name}
AND featured = 1
SELECT * FROM blog
title LIKE #{title}
AND author_name = #{author.name}
UPDATE blog
title = #{title},
author_name = #{author.name},
WHERE id = #{id}
SELECT * FROM blog
AND title LIKE #{title}
OR author_name = #{author.name}
SELECT * FROM blog WHERE id IN
#{id}
SELECT * FROM blog WHERE title LIKE #{pattern}
id, title, author_name, state
SELECT
FROM blog
``` ## 关联查询 MyBatis 中“关联查询”只有 **2 种官方语义** 1. **一对一(one-to-one)** 2. **一对多 / 多对一(one-to-many / many-to-one)** 实现方式又有 **2 套语法** A. **嵌套结果**(一条 SQL 把主表 + 从表 JOIN 回来,用 `
` 拆) B. **嵌套查询**(先查主表,再按外键发第二条 SQL,用 `
` / `
` 的 `select=` 指定第二条语句) ```xml
SELECT u.id AS u_id, u.name AS u_name, p.id AS p_id, p.number AS p_number FROM user u LEFT JOIN passport p ON u.id = p.user_id WHERE u.id = #{id}
javaType="Passport" select="selectPassportByUserId"/>
SELECT id, name FROM user WHERE id = #{id}
SELECT id, number FROM passport WHERE user_id = #{id}
SELECT u.id AS u_id, u.name AS u_name, a.id AS a_id, a.title AS a_title FROM user u LEFT JOIN article a ON u.id = a.user_id WHERE u.id = #{id}
ofType="Article" select="selectArticlesByUserId"/>
SELECT id, name FROM user WHERE id = #{id}
SELECT id, title FROM article WHERE user_id = #{id}
``` ### 5.5 关联查询总结 #### resultType 作用:将查询结果按照SQL列名与实体类属性名一致性映射到实体类对象中。 场合:常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到实体类中,在前端页面遍历list(ist中是实体类)即可。 #### resultMap 使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。 ##### association 作用:将关联查询信息映射到一个实体类对象中。 场合:为了方便查询关联信息可以使用association将关联信息映射为当前对象的一个属性,比如:查询订单以及关联用户信息。 ##### collection 作用:将关联查询信息映射到一个list集合中。 场合:为了方便查询追历关联信息可以使用collection将关联信息映射到ist集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块ist中,将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。如果使用resultType无法将查询结果映射到ist集合中。 #### resultMap的继承 resultMap标签可以通过extends属性来继承一个已有的或公共的resultMap,避免重复配置的出现,减少配置量。 ```xml
``` ## 查询缓存 数据库的数据是存储在硬盘中,如果程序需要用到数据,那么就需要频繁的从磁盘中读取数据,效率低,数据库压力大。我们可以把查询到的数据缓存起来,这样就减少了频繁操作磁盘数据,提高查询效率,减轻数据库压力。 Mybatis提供了查询缓存,用于减轻数据库压力,提高数据库性能。但是在实际项目开发中,很少使用Mybatis的缓存机制,现在主流的缓存机制是Redis。 ### 6.1 什么是查询缓存 MyBatis系统中的缓存,分别是一级缓存和二级缓存。 一级缓存是SgISession级别的缓存,在操作数据库时需要构造SqlSession对象,在对象中有一个HashMap数据结构用于存储缓存数据。不同的SgISession之间的缓存数据区域是互相不影响的。默认情况下,一级缓存是开启的。 二级缓存是Mapper(namespace)级别的缓存,多个SglSession去操作同一个mapper的sql语句,多个SglSession可以共用二级缓存,二级缓存是跨SglSession的。二级缓存需要手动开启和配置。 为了提高扩展性,MyBatis定义了缓存接口Cache,我们可以通过实现Cache接口来自定义二级缓存。 ### 6.2 一级缓存 一级缓存是基于PerpetualCache的HashMap本地缓存,作用范围为session域内。当session commit或者close关闭之后,该session中所有的cache(缓存)就会被清空。 在参数和SQL完全一样的情况下,我们使用同一个SglSession对象调用同一个mapper的方法,往往只执行一次SQL。因为使用SqlSession第一次查询后,MyBatis会将其放在缓存中,再次查询时,如果没有刷新,并且缓存没有超时的情况下,SqlSession会取出当前缓存的数据,而不会再次发送SQL到数据库。 由于SqlSession是相互隔离的,所以如果你使用不同的SqlSession对象,即使调用相同的Mapper、参数和方法,MyBatis还是会再次发送SQL到数据库执行,返回结果。 #### 一级缓存工作原理 - 第一次查询id为1的数据,先去找一级缓存中查找是否有id为1的数据,如果没有,从数据库中查询该数据,并将该数据存储到一级缓存中。 - 第二次查询id为1的数据,也先去找一级缓存中查找是否有id为1的数据,缓存中有,直接从缓存中获取该数据,不再查询数据库。 - 如果SqlSession去执行commit操作(执行插入、更新、删除),将清空SglSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的数据,避免脏读。 ### 6.3 二级缓存 #### 二级缓存工作原理 - Session1去查询id为1的数据,查询到后会将该数据存储到当前会话的一级缓存中。 - 如果会话关闭,一级缓存中的数据会被保存到二级缓存中。 - SglSession2去查询id为1的数据,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。 - 如果SqlSession3去执行相同mapper下sql,执行commit提交,清空该mapper下的二级缓存区域的数据。 - 二级缓存与一级缓存区别,二级缓存的范围更大,多个SgISession可以共享一个Mapper的二级缓存区域。 - 每个mapper有一个二级缓存区域,按namespace分。 - 如果两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。 #### 开启二级缓存 **在mybatis核心配置文件中配置:cacheEnabled**。 | 设置项 | 描述 | 允许值 | 默认值 | | ------------ | ---------------------------------------------- | ---------- | ------ | | cacheEnabled | 对在此配置文件下的所有cache进行全局性开/关设置 | true\false | true | ```xml
``` 在映射文件中开启二级缓存,mapper.xml下的SQL执行完成会存储到它的缓存区域HashMap。需要注意的是,二级缓存的作用域是针对mapper的namescape而言,即只有在此namescape内的查询才能共享这个缓存。 ```xml
..
``` **二级缓存中存储数据的实体类必须实现可序列化接口java.lo.Serializable**。 ## 分页插件 导分页插件jar包 ```xml
com.github.pagehelper
pagehelper
5.1.10
``` 配置分页插件 在MyBatis全局配置文件中配置拦截器插件 ```xml
``` PageHelper 5.x 的配置插件属性 | 参数名 | 作用描述 | 有效值 | 默认值 | | --------------------------- | ------------------------------------------------- | ------------------------------------------------------------ | ------------------ | | **helperDialect** | 强制指定数据库方言,不指定则自动探测 | oracle、mysql、mariadb、sqlite、hsqldb、postgresql、db2、sqlserver、informix、h2、sqlserver2012、derby 或自定义实现类全限定名 | *自动探测* | | **dialect** | 老版本兼容参数,等价于 helperDialect(已不推荐) | 同上 | *自动探测* | | **reasonable** | 分页合理化:pageNum≤0 查第一页,>pages 查最后一页 | true / false | **false** | | **pageSizeZero** | 当 pageSize=0 时是否返回全部结果 | true / false | **false** | | **params** | 从 Mapper 方法参数里提取分页字段的映射规则 | 形如 `pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero` | 如左默认值 | | **supportMethodsArguments** | 是否支持把分页参数写在 Mapper 方法的形参里 | true / false | **false** | | **autoRuntimeDialect** | 多数据源场景下运行时动态识别方言 | true / false | **false** | | **closeConn** | 自动探测方言时是否关闭临时获取的 Connection | true / false | **true** | | **aggregateFunctions** | 需要被识别为聚合函数的函数名(5.1.5+) | 英文逗号分隔的函数列表 | *内置常用聚合函数* | ## 注解开发 Mybatis最初配置信息是基于XML,映射语句(SQL)也是定义在XML中的。而到了MyBatis3提供了新的基于注解的配置。使用注解开发方式,可以减少编写Mapper映射文件。 #### 常用注解说明 | 功能 | 注解 | 一句话作用 | 最小示例 | | ----------------- | ----------------- | ---------------------------- | ------------------------------------------------------------ | | **新增** | `@Insert` | 写死 SQL 插入 | `@Insert("INSERT INTO user(name,age) VALUES(#{name},#{age})")` | | **更新** | `@Update` | 写死 SQL 更新 | `@Update("UPDATE user SET name=#{name} WHERE id=#{id}")` | | **删除** | `@Delete` | 写死 SQL 删除 | `@Delete("DELETE FROM user WHERE id=#{id}")` | | **查询** | `@Select` | 写死 SQL 查询 | `@Select("SELECT * FROM user WHERE id=#{id}") User selectById(Integer id);` | | **主键返回/选项** | `@Options` | 主键回填、关闭二级缓存等 | `@Insert("INSERT INTO user(name) VALUES(#{name})") @Options(useGeneratedKeys=true, keyProperty="id")` | | **结果映射** | `@Result` | 把列映射到字段 | `@Result(column="user_name", property="name")` | | **结果映射组** | `@Results` | 多个 `@Result` 打包 | `@Results(id="userMap", value={@Result(column="id",property="id"),@Result(column="name",property="name")})` | | **复用映射** | `@ResultMap` | 引用 `@Results` 定义的映射 | `@ResultMap("userMap")` | | **一对一** | `@One` | 立即或延迟加载子对象 | `@Result(column="pass_id", property="passport", one=@One(select="com.xxx.PassportMapper.selectById"))` | | **一对多** | `@Many` | 立即或延迟加载集合 | `@Result(column="id", property="articles", many=@Many(select="com.xxx.ArticleMapper.selectByUserId"))` | | **动态 SQL** | `@SelectProvider` | 用 Java 方法拼 SQL | `@SelectProvider(type=UserSqlBuilder.class, method="buildSelect")` | | **二级缓存** | `@CacheNamespace` | 开启 mapper 级缓存 | `@CacheNamespace(implementation = PerpetualCache.class, flushInterval = 60000)` | | **多参数** | `@Param` | 给形参起名,XML 里引用 | `User selectByNameAndAge(@Param("name") String n, @Param("age") Integer a);` | | **Spring 托管** | `@Mapper` | SSM 整合时让 Spring 扫描 DAO | `@Mapper public interface UserMapper { ... }` | 完整的案例: ```java @Mapper // 14. 交给 Spring 管理 @CacheNamespace // 13. 开启二级缓存 public interface UserMapper { @Insert("INSERT INTO user(name,age) VALUES(#{name},#{age})") @Options(useGeneratedKeys = true, keyProperty = "id") // 5. 主键回填 int insert(User user); @Update("UPDATE user SET name=#{name},age=#{age} WHERE id=#{id}") int update(User user); @Delete("DELETE FROM user WHERE id=#{id}") int delete(@Param("id") Integer id); // 12. 多参数命名 @Select("SELECT * FROM user WHERE id=#{id}") @Results(id="userMap", value = { // 6-8. 结果映射 & 复用 @Result(column="id", property="id"), @Result(column="name", property="name") }) User selectById(@Param("id") Integer id); // 9. 一对一:立即加载 passport @Select("SELECT * FROM user WHERE id=#{id}") @Results({ @Result(column="id", property="id"), @Result(column="pass_id", property="passport", one=@One(select="com.example.mapper.PassportMapper.selectById")) }) User selectUserWithPassport(@Param("id") Integer id); // 10. 一对多:延迟加载文章列表 @Select("SELECT * FROM user WHERE id=#{id}") @Results({ @Result(column="id", property="id"), @Result(column="id", property="articles", many=@Many(select="com.example.mapper.ArticleMapper.selectByUserId")) }) User selectUserWithArticles(@Param("id") Integer id); // 11. 动态 SQL:用 Java 方法拼 @SelectProvider(type = UserSqlBuilder.class, method = "buildSelect") List
selectByDynamic(UserQuery q); } ``` 动态 SQL 工具类(UserSqlBuilder.java) ```java public class UserSqlBuilder { public String buildSelect(UserQuery q) { return new SQL() .SELECT("*") .FROM("user") .WHERE(q.getName() != null, "name LIKE #{name}") .WHERE(q.getMinAge() != null, "age >= #{minAge}") .toString(); } } ``` ## 延迟加载 延迟加载的目的是减少内存的浪费和减轻系统负担。你可以理解为按需加载,当我调用到关联的数据时才与数据库交互否则不交互。 resultMap可以实现高级映射(使用association、collection实现一对一和一对多映射),association、collection具备延迟加教功能。 #### 打开延迟加载开关 在MyBatis核心配置文件中配置:lazyLoadingEnabled、aggresiveLazyLoading。 | 设置项 | 描述 | 允许值 | 默认值 | | --------------------- | ------------------------------------------------------------ | ---------- | ------ | | lazyLoadingEnabled | 全局性设置懒加载。如果设为false',则所有相关联的都会被初始化加载 | true,false | false | | aggressiveLazyLoading | 当设置为true的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载 | true,false | true | ```xml
``` 为了便于debug测试,在setings设置name="lazyLoadTriggerMethods" value="",表示toString()、hashCode不触发延时加载。