文章目录
一、框架作用
作为数据库整体解决方案,解决了高耦合的问题,ORM(object relation mapping)把javabean与数据库一一映射,把JDBC的操作封装
但是编写sql需要手动进行,所以mybatis把sql与java编码分离,是半自动框架
二、properties使用文件
将数据库配置信息放到properties文件中,在mybatis.xml文件中引用为reousrces
properties文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456
xml文件
<properties resource="conf/dbconfig.properties">
<!--resource:路径下的资源
url:网络路径或者磁盘下的路径-->
</properties>
``
```java
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>
三、全局配置文件
在mubatis_config.xml文件名中
可以设置自动驼峰命名,还有其他参数之后再学
<!--setting设置每一个设置项-->
<!-- <settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>-->
貌似不是很建议用这个参数
<!--typeAliases:别名处理器,可以为java类型起别名,默认是类名小写-->
<!-- <typeAliases>
<!–为某个java类型起别名,别名不区分大小写,或者用注解–>
<typeAlias type="com.uestc.mybatis.Employee" alias="emp"></typeAlias>
<!–package批量起别名,指定包名批量起名–>
<package name=""/>
</typeAliases>-->
之后做了多库再来看这个文件
<!--id为唯一标识,在default里面来指定使用某种环境(切换id),可以快速切换
transactionManager:事务管理器
type:事务管理类型 POPLED,UNPOLLED,JNDI
-->
<!-- <environments default="">
<environment id="">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>-->
三、映射文件(魔法源泉!)
1、参数处理规则
(1)单个参数
mb不做任何处理
#{参数名}:取出参数值
(2)多个参数
mb做特殊处理
多个参数会被封装成一个map
key:param1…paramN,或者参数的索引
value:传入的参数值
#{}就是从map获取指定的key值
推荐使用命名参数:明确指定封装的map和key
public Employee getEmp(@Param("id")Integer id, @Param("lastName")String last_name);
接口定义参数
<select id="getEmp" resultType="emp">
select * from tbl_employee where id = #{id} and last_name=#{lastName}
</select>
在xml文件中来对应参数值传入位置
(3)使用POJO传递多个参数
(4)使用Map来传递
用的不多
(4 )使用TO
多个参数不是业务模型中的数据,但是经常使用,推荐写一个TO(Transfer Object)数据传输对象
Page{ int index; int size}
(5)#和¥区别
#{}以预编译的形式,将参数设置到SQL,PreparedStatement
¥{}将区处得知直接拼装到sql中,有注入安全问题
但是原生jdbc不支持占位符的地方使用¥{}进行取值
2、select语句
(1)、返回List
Mapper.xml文件
<!--resultType为返回值的类型不是集合类型-->
<select id="getEmpsByLastNameLike" resultType="com.uestc.mybatis.Employee">
select * from tbl_employee where last_name like #{lastName}
</select>
Mapper接口文件
public List<Employee> getEmpsByLastNameLike(String lastName);
Test文件就可以使用通配符查询方式查询多个对象返回集合
List<Employee> like = mapper.getEmpsByLastNameLike("%a%");
(2)、返回多条记录Map集合
Mapper.xml文件
<!--resultType为返回值的类型不是集合类型-->
<select id="getEmpsByLastNameLikeReturnMap" resultType="com.uestc.mybatis.Employee">
select * from tbl_employee where last_name like #{lastName}
</select>
Mapper接口文件
@MapKey("id") //注解指明封装map的key的属性
public Map<Integer, Employee> getEmpsByLastNameLikeReturnMap(String lastName);
Test文件就可以使用通配符查询方式查询多个对象返回集合
Map<Integer, Employee> mappp = mapper.getEmpsByLastNameLikeReturnMap("%o%");
System.out.println(mappp);
```java
在这里插入代码片
(3)、resultMap自定义映射规则
可以自定义javabean与数据库中列名的映射规则
<mapper namespace="com.uestc.mybatis.EmployeeMapperPlus">
<!--自定义某个javaBean封装规则
type:自定义规则的Java类型
id:唯一方便引用-->
<resultMap id="MyEmp" type="com.uestc.mybatis.Employee">
<!--指定主键列封装规则 column指定列,property指定对应javabean属性-->
<id column="id" property="id"></id>
<!--定义普通封装规则-->
<result column="last_name" property="email"></result>
<result column="email" property="last_name"></result>
<!--其他不指定的列会自动封装,JavaBean和table中对象的属性名相同-->
</resultMap>
<!--resultMap自定义结果应设计规则-->
<select id="getEmpById" resultMap="MyEmp">
select * from tbl_employee where id=#{id};
</select>
</mapper>
比如上面我们把邮箱和名字的映射换了一下,于是测试类输出
Employee{id=1, last_name='ustc.com', email='tom', gender='0'}
真的是非常的灵活哈
(4)、联表查询
1、最基础联表查询
表结构
Mapper.xml文件
<resultMap id="DeptThing" type="com.uestc.mybatis.Employee">
<id column="id" property="id"></id>
<result column="last_name" property="last_name"></result>
<result column="gender" property="gender"></result>
<result column="email" property="email"></result>
<!-- <result column="id" property="dept.id"></result>
<result column="dept_name" property="dept.deptName"></result>-->
<association property="dept" javaType="com.uestc.mybatis.Department">
<id column="id" property="id"></id>
<result column="dept_name" property="deptName"></result>
</association>
</resultMap>
<!--查出员工对应的部门-->
<!--public Employee getEmpAndDept(Integer id);-->
<select id="getEmpAndDept" resultMap="DeptThing">
SELECT e.id, e.last_name, e.gender, e.email,d.id, d.dept_name FROM tbl_employee e INNER JOIN tbl_dept d ON e.d_id=d.id where e.id=#{id}
</select>
Employee的类属性,可以直接通过点的方式来读取,也可以通过association来封装
2、使用association分布式查询
首先需要建立公司表的Mapper接口和xml文件,定义方法和查询返回对象类型,不要忘记在mybatis配置文件中注册
<mapper namespace="com.uestc.mybatis.DepartmentMapper">
<!--public Department getDeptById(Integer id)-->
<select id="getDeptById" resultType="com.uestc.mybatis.Department">
select id, dept_name deptName from tbl_dept where id=#{id}
</select>
</mapper>
分布式查询
<!--使用association进行分步查询
1、先通过员工id查出员工信息
2、查询员工西席中的d_id值去部门表查询部门信息
3、部门信息设置到员工中-->
<resultMap id="MyEmpByStep" type="com.uestc.mybatis.Employee">
<id column="id" property="id"></id>
<result column="last_name" property="last_name"></result>
<result column="gender" property="gender"></result>
<result column="email" property="email"></result>
<!--association封装规则
select表明当前书信是调用select指定的方法查处结果
column:指定将那一列的值传给这个方法
然后把select查出的对象封装非property指定的属性-->
<association property="dept"
select="com.uestc.mybatis.DepartmentMapper.getDeptById"
column="d_id" >
</association>
</resultMap>
<!--public Employee getEmpByIdStep(Integer id);-->
<select id="getEmpByIdStep" resultMap="MyEmpByStep">
select * from tbl_employee where id=#{id}
</select>
可以看到公司xml返回的对象被封装后赋予给了员工的公司属性,进一步降低了耦合,对已有方法进行组合
可以使用延迟加载,在查询员工对象时,部门信息使用时再去查询
在mybatis配置文件中进行设置
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
3、使用collection进行分布式查询
需求:查询部门信息,同时返回部门中的员工集合
<select id="getDeptById" resultType="com.uestc.mybatis.Department">
select id, dept_name deptName from tbl_dept where id=#{id}
</select>
<!-- private Integer id;
private String deptName;
private List<Employee> emps;-->
<!--id dept_name || id last_name email gender-->
<resultMap id="MyDept!" type="com.uestc.mybatis.Department">
<id column="id" property="id"></id>
<result column="dept_name" property="deptName"></result>
<!--collection定义集合类型属性封装规则
ofType指定结合元素类型-->
<collection property="emps" ofType="com.uestc.mybatis.Employee">
<!--定义集合中元素封装规则-->
<id column="id" property="id"></id>
<result column="last_name" property="last_name"></result>
<result column="email" property="email"></result>
<result column="gender" property="gender"></result>
</collection>
</resultMap>
<select id="getDeptByIdPlus" resultMap="MyDept!">
SELECT d.id, d.dept_name,e.id, e.last_name , e.email, e.gender FROM tbl_dept d LEFT JOIN tbl_employee e ON d.id=e.d_id WHERE d.id=#{id}
</select>
下面才是分布查询,同时需要在员工接口中定义返回集合的方法
public List<Employee> getEmpsByDeptId(Integer id);
同步在mapper文件中定义查询语句
<select id="getEmpsByDeptId" resultType="com.uestc.mybatis.Employee">
select * from tbl_employee where d_id=#{dept_id}
</select>
在部门mapper中定义分布式查询语句
<resultMap id="MyDeptStep" type="com.uestc.mybatis.Department">
<id column="id" property="id"></id>
<result column="dept_name" property="deptName"></result>
<collection property="emps"
select="com.uestc.mybatis.EmployeeMapperPlus.getEmpsByDeptId"
column="id"
></collection>
</resultMap>
<select id="getDeptByIdStep" resultMap="MyDeptStep">
SELECT id,dept_name FROM tbl_dept WHERE id=#{id}
</select>
<!--如果分布式查询,要传入的值有多列,应该封装为map传递
column="{key1=column1,key2=column2} fetchType="lazy/eager""
同时在分布式被查询的地方
where x1=#{key1} ,x2=#{key2}
fetchType="lazy/eager" 分别表示延迟加载和立即加载-->
由于emps集合属性是存在于公司javabean中,不存在于公司数据库的列属性中,所以select中不含emps属性,而是通过resultMap中的collection来返回属性进行封装
四、动态SQL
五、缓存
/*两级缓存
* 一级缓存(本地缓存) sqlSession级别的缓存,一直开着起的
* 与数据库同一次会话查询到的数据会放在本地缓存中
* 以后如果获取相同的数据直接从缓存中拿,不再访问数据库
* 一级缓存失效情况(没使用到一级缓存,就需要向数据库查询)
* 1、sqlSession不同
* 2、sqlSession相同但是查询条件不同
* 3、sqlSession相同但是两次查询之间执行了增删改(可能会对当前数据有影响)
* 4、sqlSession相同,手动清空一级缓存
* openSession.clearCache();
* 二级缓存(全局缓存) 一个namespace对应一个二级缓存
* 工作机制
* 1、一个会话查询一条数据,就会放在当前会话一级缓存
* 2、如果会话关闭:以及缓存中的数据会被保存到二级缓存中
* 3、sqlSession==>EmployeeMapper==>Employee
* DepartmengtMapper==>Department
* 不同的namespace查处的数据会放在自己对应的缓存中
* 使用
* 1、开启全局二级缓存配置:<setting name="cacheEnabled" value="true">
2、mapper.xml中配置二级缓存
3、POJO需要实现序列化接口
<eviction:缓存回收策略:
* LRU(默认): 最近最少使用的;移除最长时间不被使用的对象
* FIFO:先进先出,SPFT,WEAK:JAVA虚拟机规则
* flushInterval:缓存刷新键和,默认不清空
* readOnly:是否只读
* true:只读,mybatis认为缓存中获取数据的操作都是读操作,不会修改数据,快,不安全
* false:非只读:mybatis使用序列化反序列化技术克隆一份新数据给你,安全速度慢
* >
*
* 查出的数据先放在一级缓存中,只有提交或者关闭以后,一级缓存数据才会转移到二级缓存
有关设置
* 1、cacheEnabled=false:关闭二级缓存(一级还在)
* 2、对于每个select标签都有useCache:false不使用二级缓存
* !3、每个增删改标签的flushCache=true 执行命令完成后就会清空一级缓存和二级缓存
* 4、clearCache()之清除一级缓存
*
*
但是我们流出了接口给第三方库哦,比如redis
* */