Mybatis是一个半自动化的ORM持久化框架,可以通过简单的XML或注解用与配置或原始映射,将接口和POJO对象映射成数据库中的记录
Mybatis整体架构:
1、 配置文件
全局配置文件:mybatis-config.xml作用:配置数据源,引入映射文件
映射文件:XxMapper.xml作用:配置sql语句、参数、结果集封装类型等
2、 SqlSessionFactory
作用:获取SqlSession
通过newSqlSessionFactoryBuilder().build(inputStream)来构建,inputStream:读取配置文件的IO流
3、 SqlSession
作用:执行CRUD操作
它是线程不安全的。因此最佳的使用范围是请求或方法范围。
4、 Executor
执行器,SqlSession通过调用它来完成具体的CRUD
它是一个接口,提供了两种实现:缓存的实现、数据库的实现
5、 Mapped Statement
在映射文件里面配置,包含3部分内容:
具体的sql,sql执行所需的参数类型,sql执行结果的封装类型
参数类型和结果集封装类型包括3种:
HashMap,基本数据类型,pojo
约束配置:可以通过快捷键获取xml中的所有标签
Preferences------>XML Catalog
添加两个约束:
全局配置文件的约束: http://mybatis.org/dtd/mybatis-3-config.dtd
映射文件的约束: http://mybatis.org/dtd/mybatis-3-mapper.dtd
全局配置文件:mybatis-config
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 引入外部资源文件
resource:默认引入classpath路径下的资源文件
-->
<properties resource="jdbc.properties"></properties>
<!-- 设置驼峰匹配:从数据库列名映射java属性名称的经典方式 -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 配置别名 -->
<typeAliases>
<!-- typeAlias:用来配置别名,方便映射文件使用,type:类的全限定类名,alias:别名 -->
<!-- <typeAlias type="cn.itcast.pojo.User" alias="User"/> -->
<!-- 配置包扫描:解决多个pojo别名问题,默认将类名作为笔名,大小写不敏感 -->
<package name="cn.itcast.pojo"/>
</typeAliases>
<!-- 配置环境:可以配置多个环境,default:配置某一个环境的唯一标识,表示默认使用哪个环境 -->
<environments default="development">
<!-- 配置环境,id:环境的唯一标识 -->
<environment id="development">
<!-- 事务管理器,type:使用jdbc的事务管理器 -->
<transactionManager type="JDBC"/>
<!-- 数据源,type:数据源类型,池类型的数据源 -->
<dataSource type="POOLED">
<!-- 配置连接信息 -->
<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>
<!-- 配置映射文件:用来配置sql语句和结果集类型等 -->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
映射文件配置:XxMapper.xml
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
mapper标签:配置各类声明
namespace:名称空间,由于映射文件有多个,为了防止crud语句的唯一标识被重复,可以设置空间名称。
cn.itcast.mapper.UserMapper : 对数据库CRUD操作的接口方法类似于IUserDao
名称空间必须改成UserMapper接口的全路径,StatementId必须和接口方法名一致,结果集的封装类型已经和方法的返回类型一致
-->
<mapper namespace="cn.itcast.mapper.UserMapper">
<!—
select:查询的statement(声明),用来编写查询语句
id:语句的唯一标识
resultType:配置返回的结果集类型
-->
<select id="queryUserById" resultType="User">
select * from tb_user where id = #{id}
</select>
</mapper>
测试类:
private UserMapper userMapper;
//获取全局配置文件输入流
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//加载全局配置文件
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取sqlSession并自动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//通过动态代理生成一个代理的实现类
userMapper = sqlSession.getMapper(UserMapper.class);
public void testQueryUserById() {
User user = userMapper.queryUserById(1L);
System.out.println(user);
}
全局配置文件:mybatis-config 标签总结:
Properties:引入外部资源文件
Settings:配置驼峰命名方式,类似经典的数据库字段名和java类中属性的映射关系。
typeAliases:配置别名
typeHandler:类型转换器
plugings:插件,又称之为拦截器(分页助手、通用mapper)
environments:可以配置多个环境
environment:配置环境
transactionManager:配置事务管理器
dataSource:配置数据源
mappers:配置映射文件
Package:通过包名配置映射文件
映射文件配置:XxMapper.xml 标签详解:
Select标签:用来编写查询语句的statement
id属性:唯一标识
resultType:查询语句返回的结果集类型
parameterType:参数类型,使用动态代理之后,需要和mapper接口中的参数类型一致,可以省略。
Insert标签:编写新增语句的statement
insert:编写插入语句
id:插入语句的唯一标识
parameterType:插入语句的参数类型,使用动态代理之后,需要和mapper接口中的参数类型一致,可以省略。
useGeneratedKeys:开启主键自增回显,将自增长的主键值回显到形参中(即封装到User对象中)
keyColumn:数据库中主键的字段名称
keyProperty:pojo中主键对应的属性
Update标签:编写更新语句的statement
id:语句的唯一标识
parameterType:语句的参数类型,使用动态代理之后,需要和mapper接口中的参数类型一致,可以省略。
delete标签:编写删除语句的statement
id:语句的唯一标识
parameterType:语句的参数类型,使用动态代理之后,需要和mapper接口中的参数类型一致,可以省略。
CRUD标签都有一个属性parameterType,statement通过它指定接收的参数类型。
接收参数的方式有两种:
1、 #{}预编译(传入的值会加"")
2、${}非预编译(直接的sql拼接,不能防止sql注入)
参数类型有三种:
1、 基本数据类型
2、 HashMap(使用方式和pojo类似)
3、 Pojo自定义包装类型
使用@Param注解指定参数名:@Param("userName")String userName,然后再在statement中调用#{userName}或${userName}
ResultMap是mybatis中最重要最强大的元素,使用ResultMap可以解决两大问题:
1. POJO属性名和表结构字段名不一致的问题(有些情况下也不是标准的驼峰格式,比如id和userId)
2. 完成高级查询,比如说,一对一、一对多、多对多.
一:配置resultMap
<!--
resultMap标签:可以自己配置对象属性和表字段的映射(不仅仅是驼峰规则的映射)
type属性:结果集的封装类型
id属性:唯一标识
autoMapping属性:如果不配置,默认为true。对其他属性进行自动映射。
-->
<resultMap type="User" id="userResultMap" autoMapping="true">
<!-- id标签:配置主键映射,column:表中的字段名称,property:属性名称 -->
<id column="id" property="id"/>
<!-- 可以用来配置普通类型字段和属性映射(非复杂类型) -->
<result column="user_name" property="userName"/>
</resultMap>
二:将statement中的resultType属性改为 resultMap:userResultMap
问题:
字段和属性名称都匹配的字段要不要配置?
这个取决于resultMap中的autoMapping属性的值:
为true时:resultMap中的没有配置的字段会自动对应。如果不配置,则默认为true。
为false时:只针对resultMap中已经配置的字段作映射。
将重复的sql片段抽取为一个xml配置文件:
一:新建一个xml文件CommonSql.xml(需要mapper的约束)
<?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="CommonSQL">
<sql id="commonSql">
id,
user_name,
password,
name,
age,
sex,
birthday,
created,
updated
</sql>
</mapper>
二:引入全局配置
<mapper resource="CommonSql.xml" />
三:最后在需要使用该sql片段的地方通过include标签的refId属性引用该sql片段:<include refId="CommonSql.commonSql" />
refId=名称空间.sql片段的id
动态sql:
1、if
2、choose when otherwise
choose标签:条件选择
when子标签:编写条件,不管有多少个when条件,一旦其中一个条件成立,后面的when条件都不执行。
test属性:编写ognl表达式
otherwise子标签:当所有条件都不满足时,才会执行该条件。
3、where标签
可以自动将动态sql中多出来的一个and或者or去除。
4、set标签:
可以用在update的statement中,自动添加一个set关键字,并且会将动态sql最后多余的逗号去除。
5、foreach标签:遍历集合
collection属性:接收的集合参数
item属性:集合参数中的每一个元素
separator属性:标签逗号分隔符
open属性:以什么开始
close属性:以什么结束
mybatis的缓存机制:
一级缓存:一级缓存默认是开启的(不管你用或不用,她一直都在),作用域:在同一个sqlSession下
二级缓存:
1、 同一个mapper的namespace,在同一个namespace中查询sql可以从缓存中命中。
2、 跨sqlSession,不同的SqlSession可以从二级缓存中命中
高级查询:
注意:一旦涉及到嵌套映射,一定要设置手动设置为自动映射。不管是Order的自动映射还是User的自动映射都需要手动设置为true。
resultMap中的数据其他地方也要用到,那么可以使用继承的方法来复用即可 extends="orderUserMap"
一对一:
<resultMap type="Order" id="orderUserMap" autoMapping="true">
<id property="id" column="id"/>
<!--
association:用于对一的映射
property:类中的关联属性的名称
javaType:属性对应的类型
autoMapping:添加自动映射,一旦涉及到嵌套查询,需要手动设置为true
-->
<association property="user" javaType="User" autoMapping="true">
<!--
id:关联对象的主键
property:关联对象的主键名称
column:关联对象在表中对应的字段名称,如果重名,可以使用别名
-->
<id property="id" column="uid"/>
</association>
</resultMap>
一对多:
<resultMap type="Order" id="orderUserMap" autoMapping="true" extends="orderUserMap">
<collection property="detailList" javaType="List" ofType="Orderdetail" autoMapping="true">
<!--
property:类中的对应主键的属性名称
column:表中的字段名称,可以使用自己在sql语句中设置的别名,注意不要使用结果中有mysql自动设置的别名,如id2
-->
<id property="id" column="detail_id"/>
</collection>
</resultMap>
多对多:
<resultMap type="Order" id="orderUserMap" autoMapping="true" extends="orderUserMap">
<collection property="detailList" javaType="List" ofType="Orderdetail">
<!--
property="id":关联对象的主键的属性名称
column:关联对象在表中的主键名称,如果重复,可以使用别名
-->
<id property="id" column="detail_id"/>
<!-- 通过Orderdetail对一查询Item -->
<association property="item" javaType="Item" autoMapping="true">
<!--
property:item的主键的属性名称
column:表中主键的字段名称,如果重名,可以使用别名,或者外键名称
-->
<id property="id" column="iid"/>
</association>
</collection>
</resultMap>
延迟加载:
一:两个statement就分别相当于两条查询order和查询user的sql语句,然后通过resultMap将延迟加载的查询user的statement关联到查询查询order的statement上。使得在查询order之后,
<resultMap type="Order" id="orderUserLazyMap" autoMapping="true">
<id property="id" column="id"/>
<!-- 关联查询user
select:延迟加载user,通过调用另外的user的statement来发送第二个语句查询user
column:查询user的参数,该id的信息其实是在查询出来的order中的user_id
如果参数有多个,可以使用{user_id=id,user_name = userName}的方式来传参
-->
<association property="user" javaType="User" select="queryUserByUserIdOfOrder" column="user_id"></association>
</resultMap>
<!-- 通过order_number查询order -->
<select id="queryOrderUserLazy" resultMap="orderUserLazyMap">
select * from tb_order where order_number = #{orderNumber}
</select>
<!-- 通过order中的user_id查询user -->
<select id="queryUserByUserIdOfOrder" resultType="User">
select * from tb_user where id = #{id}
</select>
二:开启延迟加载开关
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
三:添加cglib的依赖
<!-- cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
Mybatis整体架构:
1、 配置文件
全局配置文件:mybatis-config.xml作用:配置数据源,引入映射文件
映射文件:XxMapper.xml作用:配置sql语句、参数、结果集封装类型等
2、 SqlSessionFactory
作用:获取SqlSession
通过newSqlSessionFactoryBuilder().build(inputStream)来构建,inputStream:读取配置文件的IO流
3、 SqlSession
作用:执行CRUD操作
它是线程不安全的。因此最佳的使用范围是请求或方法范围。
4、 Executor
执行器,SqlSession通过调用它来完成具体的CRUD
它是一个接口,提供了两种实现:缓存的实现、数据库的实现
5、 Mapped Statement
在映射文件里面配置,包含3部分内容:
具体的sql,sql执行所需的参数类型,sql执行结果的封装类型
参数类型和结果集封装类型包括3种:
HashMap,基本数据类型,pojo
约束配置:可以通过快捷键获取xml中的所有标签
Preferences------>XML Catalog
添加两个约束:
全局配置文件的约束: http://mybatis.org/dtd/mybatis-3-config.dtd
映射文件的约束: http://mybatis.org/dtd/mybatis-3-mapper.dtd
全局配置文件:mybatis-config
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 引入外部资源文件
resource:默认引入classpath路径下的资源文件
-->
<properties resource="jdbc.properties"></properties>
<!-- 设置驼峰匹配:从数据库列名映射java属性名称的经典方式 -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 配置别名 -->
<typeAliases>
<!-- typeAlias:用来配置别名,方便映射文件使用,type:类的全限定类名,alias:别名 -->
<!-- <typeAlias type="cn.itcast.pojo.User" alias="User"/> -->
<!-- 配置包扫描:解决多个pojo别名问题,默认将类名作为笔名,大小写不敏感 -->
<package name="cn.itcast.pojo"/>
</typeAliases>
<!-- 配置环境:可以配置多个环境,default:配置某一个环境的唯一标识,表示默认使用哪个环境 -->
<environments default="development">
<!-- 配置环境,id:环境的唯一标识 -->
<environment id="development">
<!-- 事务管理器,type:使用jdbc的事务管理器 -->
<transactionManager type="JDBC"/>
<!-- 数据源,type:数据源类型,池类型的数据源 -->
<dataSource type="POOLED">
<!-- 配置连接信息 -->
<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>
<!-- 配置映射文件:用来配置sql语句和结果集类型等 -->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
映射文件配置:XxMapper.xml
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
mapper标签:配置各类声明
namespace:名称空间,由于映射文件有多个,为了防止crud语句的唯一标识被重复,可以设置空间名称。
cn.itcast.mapper.UserMapper : 对数据库CRUD操作的接口方法类似于IUserDao
名称空间必须改成UserMapper接口的全路径,StatementId必须和接口方法名一致,结果集的封装类型已经和方法的返回类型一致
-->
<mapper namespace="cn.itcast.mapper.UserMapper">
<!—
select:查询的statement(声明),用来编写查询语句
id:语句的唯一标识
resultType:配置返回的结果集类型
-->
<select id="queryUserById" resultType="User">
select * from tb_user where id = #{id}
</select>
</mapper>
测试类:
private UserMapper userMapper;
//获取全局配置文件输入流
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//加载全局配置文件
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取sqlSession并自动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//通过动态代理生成一个代理的实现类
userMapper = sqlSession.getMapper(UserMapper.class);
public void testQueryUserById() {
User user = userMapper.queryUserById(1L);
System.out.println(user);
}
全局配置文件:mybatis-config 标签总结:
Properties:引入外部资源文件
Settings:配置驼峰命名方式,类似经典的数据库字段名和java类中属性的映射关系。
typeAliases:配置别名
typeHandler:类型转换器
plugings:插件,又称之为拦截器(分页助手、通用mapper)
environments:可以配置多个环境
environment:配置环境
transactionManager:配置事务管理器
dataSource:配置数据源
mappers:配置映射文件
Package:通过包名配置映射文件
映射文件配置:XxMapper.xml 标签详解:
Select标签:用来编写查询语句的statement
id属性:唯一标识
resultType:查询语句返回的结果集类型
parameterType:参数类型,使用动态代理之后,需要和mapper接口中的参数类型一致,可以省略。
Insert标签:编写新增语句的statement
insert:编写插入语句
id:插入语句的唯一标识
parameterType:插入语句的参数类型,使用动态代理之后,需要和mapper接口中的参数类型一致,可以省略。
useGeneratedKeys:开启主键自增回显,将自增长的主键值回显到形参中(即封装到User对象中)
keyColumn:数据库中主键的字段名称
keyProperty:pojo中主键对应的属性
Update标签:编写更新语句的statement
id:语句的唯一标识
parameterType:语句的参数类型,使用动态代理之后,需要和mapper接口中的参数类型一致,可以省略。
delete标签:编写删除语句的statement
id:语句的唯一标识
parameterType:语句的参数类型,使用动态代理之后,需要和mapper接口中的参数类型一致,可以省略。
CRUD标签都有一个属性parameterType,statement通过它指定接收的参数类型。
接收参数的方式有两种:
1、 #{}预编译(传入的值会加"")
2、${}非预编译(直接的sql拼接,不能防止sql注入)
参数类型有三种:
1、 基本数据类型
2、 HashMap(使用方式和pojo类似)
3、 Pojo自定义包装类型
使用@Param注解指定参数名:@Param("userName")String userName,然后再在statement中调用#{userName}或${userName}
ResultMap是mybatis中最重要最强大的元素,使用ResultMap可以解决两大问题:
1. POJO属性名和表结构字段名不一致的问题(有些情况下也不是标准的驼峰格式,比如id和userId)
2. 完成高级查询,比如说,一对一、一对多、多对多.
一:配置resultMap
<!--
resultMap标签:可以自己配置对象属性和表字段的映射(不仅仅是驼峰规则的映射)
type属性:结果集的封装类型
id属性:唯一标识
autoMapping属性:如果不配置,默认为true。对其他属性进行自动映射。
-->
<resultMap type="User" id="userResultMap" autoMapping="true">
<!-- id标签:配置主键映射,column:表中的字段名称,property:属性名称 -->
<id column="id" property="id"/>
<!-- 可以用来配置普通类型字段和属性映射(非复杂类型) -->
<result column="user_name" property="userName"/>
</resultMap>
二:将statement中的resultType属性改为 resultMap:userResultMap
问题:
字段和属性名称都匹配的字段要不要配置?
这个取决于resultMap中的autoMapping属性的值:
为true时:resultMap中的没有配置的字段会自动对应。如果不配置,则默认为true。
为false时:只针对resultMap中已经配置的字段作映射。
将重复的sql片段抽取为一个xml配置文件:
一:新建一个xml文件CommonSql.xml(需要mapper的约束)
<?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="CommonSQL">
<sql id="commonSql">
id,
user_name,
password,
name,
age,
sex,
birthday,
created,
updated
</sql>
</mapper>
二:引入全局配置
<mapper resource="CommonSql.xml" />
三:最后在需要使用该sql片段的地方通过include标签的refId属性引用该sql片段:<include refId="CommonSql.commonSql" />
refId=名称空间.sql片段的id
动态sql:
1、if
2、choose when otherwise
choose标签:条件选择
when子标签:编写条件,不管有多少个when条件,一旦其中一个条件成立,后面的when条件都不执行。
test属性:编写ognl表达式
otherwise子标签:当所有条件都不满足时,才会执行该条件。
3、where标签
可以自动将动态sql中多出来的一个and或者or去除。
4、set标签:
可以用在update的statement中,自动添加一个set关键字,并且会将动态sql最后多余的逗号去除。
5、foreach标签:遍历集合
collection属性:接收的集合参数
item属性:集合参数中的每一个元素
separator属性:标签逗号分隔符
open属性:以什么开始
close属性:以什么结束
mybatis的缓存机制:
一级缓存:一级缓存默认是开启的(不管你用或不用,她一直都在),作用域:在同一个sqlSession下
二级缓存:
1、 同一个mapper的namespace,在同一个namespace中查询sql可以从缓存中命中。
2、 跨sqlSession,不同的SqlSession可以从二级缓存中命中
高级查询:
注意:一旦涉及到嵌套映射,一定要设置手动设置为自动映射。不管是Order的自动映射还是User的自动映射都需要手动设置为true。
resultMap中的数据其他地方也要用到,那么可以使用继承的方法来复用即可 extends="orderUserMap"
一对一:
<resultMap type="Order" id="orderUserMap" autoMapping="true">
<id property="id" column="id"/>
<!--
association:用于对一的映射
property:类中的关联属性的名称
javaType:属性对应的类型
autoMapping:添加自动映射,一旦涉及到嵌套查询,需要手动设置为true
-->
<association property="user" javaType="User" autoMapping="true">
<!--
id:关联对象的主键
property:关联对象的主键名称
column:关联对象在表中对应的字段名称,如果重名,可以使用别名
-->
<id property="id" column="uid"/>
</association>
</resultMap>
一对多:
<resultMap type="Order" id="orderUserMap" autoMapping="true" extends="orderUserMap">
<collection property="detailList" javaType="List" ofType="Orderdetail" autoMapping="true">
<!--
property:类中的对应主键的属性名称
column:表中的字段名称,可以使用自己在sql语句中设置的别名,注意不要使用结果中有mysql自动设置的别名,如id2
-->
<id property="id" column="detail_id"/>
</collection>
</resultMap>
多对多:
<resultMap type="Order" id="orderUserMap" autoMapping="true" extends="orderUserMap">
<collection property="detailList" javaType="List" ofType="Orderdetail">
<!--
property="id":关联对象的主键的属性名称
column:关联对象在表中的主键名称,如果重复,可以使用别名
-->
<id property="id" column="detail_id"/>
<!-- 通过Orderdetail对一查询Item -->
<association property="item" javaType="Item" autoMapping="true">
<!--
property:item的主键的属性名称
column:表中主键的字段名称,如果重名,可以使用别名,或者外键名称
-->
<id property="id" column="iid"/>
</association>
</collection>
</resultMap>
延迟加载:
一:两个statement就分别相当于两条查询order和查询user的sql语句,然后通过resultMap将延迟加载的查询user的statement关联到查询查询order的statement上。使得在查询order之后,
<resultMap type="Order" id="orderUserLazyMap" autoMapping="true">
<id property="id" column="id"/>
<!-- 关联查询user
select:延迟加载user,通过调用另外的user的statement来发送第二个语句查询user
column:查询user的参数,该id的信息其实是在查询出来的order中的user_id
如果参数有多个,可以使用{user_id=id,user_name = userName}的方式来传参
-->
<association property="user" javaType="User" select="queryUserByUserIdOfOrder" column="user_id"></association>
</resultMap>
<!-- 通过order_number查询order -->
<select id="queryOrderUserLazy" resultMap="orderUserLazyMap">
select * from tb_order where order_number = #{orderNumber}
</select>
<!-- 通过order中的user_id查询user -->
<select id="queryUserByUserIdOfOrder" resultType="User">
select * from tb_user where id = #{id}
</select>
二:开启延迟加载开关
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
三:添加cglib的依赖
<!-- cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>