Mybatis
# Mybatis
# 配置
核心配置文件:MyBatis相关配置在configuration中配置
①properties标签引入资源文件,在资源文件保存键值对然后通过${key}来访问value内容
②typeAliases设置JAVA类别名,在其他地方引用直接以类名标识不需要路径,可配置整个包的类
③mapper映射文件,可以直接以包的形式导入包下面所有的映射文件,条件是映射文件和mapper接口的名称和路径要完全一致。
<configuration> <properties resource="jdbc.properties"></properties> <typeAliases > <package name="pojo"></package> </typeAliases> <mappers> <package name="mapper"></package> </mappers> </configuration>1
2
3
4
5
6
7
8
9映射文件:①namespace要保证和映射的类接口保持一致②sql语句的id要和代理接口方法名保持一致③如果是查询语句则在sql操作标签还需要设置resultType(设置每行查询结果返回java类型,而不是接口返回的List类型)和resultMap(一对多映射关系)。
<mapper namespace="pojo.User"> <!-- int insertUser--> <insert id="insertUser"> insert into t_user values(0,'admin','123456',23,'男','12345@qq.com') </insert> <select id="getUserById" resultType="pojo.User"> select * from t_user where id=1 </select> </mapper>1
2
3
4
5
6
7
8
9
10把映射文件引入到核心配置文件中
<mapper resource="mapper/UserMapper.xml"></mapper>1
# 使用
创建一个sql工厂构造器=>从流中获取创建sqlSessionFactory=>sqlSession通过代理模式创建mapper实例对象。
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取UserMapper的代理实现类对象,底层有一个代理类来实现这个类
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int result = userMapper.insertUser();
2
3
4
5
6
7
# 动态sql语句获取参数值
#{}占位符赋值多用,${}通过String字符串拼接的方式(动态设置一些查询信息),对于日期或者字符串类型需要在mapper.xml中的sql语句中手动添加单引号。多个参数的情况下,在mapper.xml通过arg0,arg1...对应拿到接口形参第一个值,第二个值...(mybatis默认放在map集合里面)
select * from t_user where username=#{arg0} and password=#{arg1}1传入形参为一个实例对象,要把实例对象的属性赋值注入xml的sql语句中,直接通过#{}访问属性名
select * from t_user where username=#{username} and password=#{password}1使用注解命名参数User getByUser(@Param('username' ) String username)
当查询语句返回多条记录时,可以直接转换成实体类,接口中返回类型设置List<User>,然后mapper.xml中sql语句的resultType设置为“User”。
当多条记录不需要转换成实体类时,接口中可以设置返回List<Map<String,Object>>,一个map映射表,在mapper.xml中sql语句resultType设置为Map。
模糊查询:使用时#{}因为在单引号里面占位符不被解析,因此使用双引号。
select * from t_user where username like "%"#{username}"#"1插入数据时自动获取到自增的数据id,存放在形参实体的id属性中
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> insert ... </insert>1
2
3
# 自定义映射
数据库列名和类属性名不一致,使用resultMap把字段名和属性名进行映射。
id标签处理主键字段,result标签处理普通字段
<resultMap id="resMap" type="User"> <id column="user_id" property="userId"></id> <result column="user_name" property="userName"></result> </resultMap> ----通过id使用----- <select id="selectAll" resultMap="resMap"></select>1
2
3
4
5
6一对一:在resultmap中添加子实例属性和对应多表联查记录的列名
public class User{ ... Dept dept;} -------mapper.xml------ <resultMap id="resMap" type="User"> <id column="user_id" property="userId"></id> <result column="user_name" property="userName"></result> <result column="dept_id" property="dept.id"></result> #直接通过.建立新映射 </resultMap>1
2
3
4
5
6
7
8
9多表查询:查到二号员工的个人信息和部门信息
方法①sql语句直接一步到位,返回的一个join的联合表记录中,把对应需要的值通过resultMap配给相应类的属性。注意这里result中重复的数据表属性不需要指明是哪个表。
<resultMap id="resMap" type="Emp"> <id column="emp_id" property="emp_id"></id> ---不需要指明是e.dept_id还是d.dept_id------ <result column="dept_id" property="dept.id"></result> <result column="dept_name" property="dept.name"></result> </resultMap> <select id="getByDeptId" resultMap="resMap"> select * from t_emp e join t_dept d on e.dept_id=d.dept_id where e.dept_id=#{id} </select>1
2
3
4
5
6
7
8
9
10方法②使用association分布查询,延迟加载的好处在于可以懒加载,使用第二个表信息才执行第二次查询。select是分布查询的唯一标识
<resultMap id="resMap" type="Emp"> <id column="emp_id" property="emp_id"></id> #当前Emp类的dept属性映射 <association property="dept" fetchType="eager/lazy" #定位到另一个返回Dept类型的sql语句唯一标识(另一个mapper.xml的namespace+id,也就是接口+方法名) select="mapper.DeptMapper.getByDeptId" #当前第一次查询记录中作为下一次查询的字段,注意是数据库的字段 column="dept_id"> </association> </resultMap> <select id="getByEmpId" resultMap="resMap"> select * from t_emp where dept_id=#{id} </select>1
2
3
4
5
6
7
8
9
10
11
12
13
14在configuration中设置全局延迟加载和按需加载
<setting name="lazyLoadingEnabled" value="true"></setting> <setting name="aggressiveLazyLoading" value="false"></setting>1
2一对多:在“一”类里面创建一个List<"多">的属性。mapper.xml使用collection
ofType设置集合里面的对象类型
<collection property="emps" ofType="Emp"> <id></id> <result></result> </collection>1
2
3
4
# 动态SQL
if:条件为真则将if标签内的内容拼接到sql语句中(使用where/trim标签)
<select id="getEmpByCondition" resultType="Emp"> select * from t_emp where 1=1 <if test="emp_name !=null and emp_name!=''"> and emp_name=#{emp_name} </if> </select>1
2
3
4
5
6where(自动生成where,自动过滤标签内容前多余的and),choose,when(相当于真正的if-else,只要一个when为真拼接当前when的条件,然后下面的when都无效)
foreach实现批量添加和批量删除,注意要给list添加形参Param注解emps,否则mybatis都会把容器类型list/array作为键添加到map中。
<insert id="insertEmp"> insert into t_emp values <foreach collection="emps" item="emp" separator=","> (null,#{emp.emp_name},#{emp.age},#{emp.gender},null) </foreach> </insert>1
2
3
4
5
6使用open="(",close=")"实现delete in(,...,)
# 缓存
- 一级缓存是SqlSession级别,同一个SqlSession的查询结果会被缓存。失效的情况:
- 不同查询条件(即使能查到同一条记录
- 两次查询之间使用一次增删改(增删改会清除缓存)
- 二级缓存是SqlSessionFactory级别。SqlSession.close关闭后才会把一级缓存保存到二级缓存,且类需要实现序列化接口。失效情况:
- 增删改
- 先查二级缓存然后再查一级缓存。二级缓存可以使用第三方缓存
# 逆向工程和分页
创建好数据库之后插件自动创建sql语句和mapper和pojo实体类
分页插件(原理:Spring给SqlSessionFactory添加拦截器,会在sql执行前添加limit,然后将查询结果和分页信息封装成PageInfo返回)
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Page<Object> page = PageHelper.startPage(1, 2); List<Emp> emps = mapper.selectByExample(null); System.out.println(page);1
2
3
4