Mybatis
作用
-
是一款优秀的持久层框架 支持定制化的sql 存储过程以及高级映射
-
之前我们学过的所有的JDBC代码和手动设置参数获取结果集 都不用写了
-
使用简单的XML配置文件或者注解 来映射原生信息 更加的方便
持久化
持久化把数据存储在磁盘而不是内存
-
程序产生的数据首先都是在内存
-
内存不可靠 我们需要一些技术把数据永久存储在硬盘上
持久层
之前的Dao层 之前通过反射 通过泛型 通用的Dao 我们在操作不同的表或者逻辑的时候 我们之前会创建一个接口 在创建接口的实现类 实际上这个dao层 就叫持久层(让数据持久化的层)
优缺点
-
sql语句与代码分离 寄存于xml文件中(最牛X的特点)
-
优点:便于维护管理 不用在java代码中找sql语句
-
缺点:不能通过打断点的方式调试,通过日志来解决这个问题
-
-
动态sql语句(最牛X的特点)
-
优点:通过逻辑标签代替编写逻辑代码 生成不同的sql
-
缺点:拼接一些比较复杂的sql语句时,没有直接拼接更直观
-
-
查询结果和java对象自动映射
-
优点:保证名称之间的对应关系 可以下划线和驼峰自动转换
-
缺点:对开发人员的sql语句以来很强
-
XML配置文件
约束
保证我们的xml能够使用哪些标签 保证xml的有效性
主配置文件xml
外部配置文件
<properties resource="db.properties"></properties>
<dataSource type="com.jsoft.datasource.DruidDataSourceFactory">
<!-- 获取配置文件的值${key} -->
<property name="druid.driverName" value="${druid.driverName}"/>
<property name="druid.url" value="${druid.url}"/>
<property name="druid.username" value="${druid.username}"/>
<property name="druid.password" value="${druid.password}"/>
</dataSource>
别名
<!--别名 给实体类起别名-->
<typeAliases>
<!-- 给单个类起别名-->
<typeAlias type="com.jsoft.entity.User" alias="user"></typeAlias>
<!-- 当前包下的所有的实体类 都以类名的首字母小写来设置别名 -->
<package name="com.jsoft.entity"/>
<!-- 场景:当前包下的某个类不想以类名小写来当作别名 使用注解@Aliases-->
</typeAliases>
<?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>
<!--environments 环境们 配置数据库连接相关 可以配置多个数据库连接-->
<environments default="development">
<environment id="development">
<!--事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据源配置 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1/lyh_db03?useUnicode=true&characterEncoding=utf-8/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
</configuration>
另外一个xml
第一次使用Mybatis 需要两个文件
-
一个接口类mapper(就是咱们之前写的dao)java文件 不需要我们写实现类
-
一个接口对应一个xml文件
-
两个文件的名字最好相同 UserMapper.java -> UserMapper.xml
-
框架会根据mapper和xml联合 通过代理模式创建实现类
-
一般情况下 我们管接口对应的xml的文件叫映射文件
sql语句传参规定
能只传一个对象 就只传一个对象
传多个参数时 不超过三个(效率低) 类型要相同 例如 都是封装类或集合 尽量不要传不同的类(效率太低)
如果传入的是User对象 在mapper.xml 映射文件中 就必须和对象的属性名匹配
如果传入的是Java内置的数据类型的参数 String,Integer。。
-
如果只传入一个参数 直接使用#{参数名} #{param1} #{XXX}
-
如果传入多个参数 必须使用#{param1} #{arg0} 不能用#{参数名}
原理:
Mybatis 在封装参数的时候 封装成了一个Map集合
-
如果传入的是一个封装对象 例User value{“username” :“admin” , “password”:“123456”}
-
如果传入的是一个内置类型的参数 字面量 【"xxx":"admin"】
-
如果传入的是多个参数 【"param1":"admin"】,【"param2":"123456"】
-
底层封装的map集合 arg0和arg1 起了个别名叫param1 param2
-
如果用arg0 param1来命名 代码可读性极差
-
使用别名 @Param ("命名") 传参
-
-
如果传入的是集合 【"param1":"{1,2,3,4,5}"】
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace: 对应mapper接口的全类名 -->
<mapper namespace="com.jsoft.dao.UserMapper">
<!-- 写sql语句 -->
<!--
id mapper接口中的方法名
resultType 方法的返回值类型 如果时entity类型 需要全类名
parameterType 方法的入参的类型 可以省略
#{id} 代表方法的入参 类似于之前的? 占位符 Mybatis底层使用的是什么? PreparedStatement
-->
<select id="selectUserById" resultType="com.jsoft.entity.User" parameterType="">
select id,username,password from user where id = #{id}
</select>
</mapper>
映射文件最终要交给mybatis去处理,所有的映射文件需要在主配置文件中进行注册。
<?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>
<!-- environments:环境们
配置数据库连接相关。可以配置多个数据库连接
-->
<environments default="development">
<environment id="development">
<!-- 事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据源配置 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1/ssm?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 注册各个映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
测试类
可以将重复的语句 使用@Before @After 注释
@Before 在所有方法执行之前执行
@after 在所有方法执行之执行
public class UserMapperTest {
SqlSession session;
UserMapper mapper
@Before
public void before(){
InputStream inputStream = UserMapperTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 获取session
session = sqlSessionFactory.openSession();
//获取对应的mapper
mapper = session.getMapper(UserMapper.class);
}
@After
public void after(){
try {
session.commit();
session.close();
}catch(Exception e){
e.printStackTrace();
session.rollback();
}
}
@Test
public void testSelectUserById(){
// 调接口里的方法
User user = mapper.selectUserById(1);
System.out.println(user);
}
}
Mybatis有两种方式可以提交事务
1.通过session调用commit方法
2.关闭session
在Mybatis的映射文件中 $和#的区别?
$ 底层使用的是Statement 拼串
·#· 底层使用的时PrepareStatement 预编译 #相当于占位符
如果想要做模糊查询 在我们java代码层面去解决%问题
自定义数据源
<!-- 引入外部的资源文件 -->
<properties resource="db.properties"/>
<environments default="development">
<environment id="development">
<!-- 事务管理 -->
<transactionManager type="JDBC"/>
<!-- 数据源配置 -->
<!--
type:
1、UNPOOLED:不使用连接池
2、POOLED:使用Mybatis默认的连接池
3、JNDI:使用JNDI实现的数据源
4、使用我们自定义的连接池实现,需要我们去写一个具体的实现类
-->
<dataSource type="com.jsoft.datasource.DruidDataSourceFactory">
<!-- property标签中的name属性只需要按照druid的命名规则命名即可 -->
<property name="druid.driverName" value="${druid.driverName}"/>
<property name="druid.url" value="${druid.url}"/>
<property name="druid.username" value="${druid.username}"/>
<property name="druid.password" value="${druid.password}"/>
</dataSource>
</environment>
</environments>
别名处理
<typeAliases>
<!-- <typeAlias type="com.jsoft.entity.User" alias="user"></typeAlias> -->
<!-- 当前包下的所有的实体类都是以类名的首字母小写来设置别名 -->
<!-- 场景:当前包下的某个类不想以类名小写来当做别名 -->
<package name="com.jsoft.entity"/>
</typeAliases>
Mybatis缓存
一级缓存最大的共享范围就是一个SqlSession内部
当二级缓存开启后,同一个命名空间(namespace) 所有的操作语句,都影响着一个共同的 cache,也就是二级缓存被多个 SqlSession 共享,是一个全局的变量
。
当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。
缓存标签的配置
设置 cache 标签的属性 cache 标签有多个属性
eviction: 缓存回收策略,有这几种回收策略
-
LRU - 最近最少回收,移除最长时间不被使用的对象
-
FIFO - 先进先出,按照缓存进入的顺序来移除它们
-
SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象
-
WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象
默认是 LRU 最近最少回收策略
-
flushinterval 缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一
个毫秒值
-
readOnly : 是否只读;true 只读,MyBatis 认为所有从缓存中获取数据的操作
都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓
存中的引用交给用户。不安全,速度快。读写(默认):MyBatis 觉得数据可能会被修
改
-
size : 缓存存放多少个元素
-
type : 指定自定义缓存的全类名(实现Cache 接口即可)
-
blocking : 若缓存中找不到对应的key,是否会一直blocking,直到有对应的
数据进入缓存。
部分设置 和 一级缓存开启(主配置文件中设置 默认开启)
<settings>
<!-- 数据库的字段名以下划线命名的自动转换成小驼峰 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 日志实现:记录发生过的事情,主要是记录在本地,后期运营维护 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- mybatis中,如果说这个settings配置的属性,用得到,尽量把它写出来 -->
<!-- 开启一级缓存,默认开启 -->
<setting name="cacheEnabled" value="true"/>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
具体的mapper配置文件中开启
<!-- 开启二级缓存 -->
<!--
eviction:缓存满了的淘汰机制
1.LRU:最近最少使用的,最长时间不适用的
2.FIFO:先进先出
3.SOFT:软引用,基于垃圾回收器状态的软引用规则
4.WEAK:弱引用,基于垃圾回收机状态的弱引用规则
flushInterval:刷新时间间隔,单位毫秒
size:缓存最多可以存多少个对象,一般情况下1024个,不宜设置过大
redOnly:只读,默认是false,不允许修改缓存
-->
<cache eviction="LRU" flushInterval="10000"/>
集合处理
<resultMap id="deptEmpResult" type="dept">标签:xml,mapper,缓存,Mybatis,mybatis,session,MyBatis From: https://www.cnblogs.com/lyh15552012044/p/16778680.html
<id property="id" column="did"></id>
<result property="name" column="dname"></result>
<collection property="employees" ofType="employee" select="com.jsoft.dao.EmployeeMapper.getEmpByDid" column="id">
</collection>
</resultMap>
<select id="findAllDepts" resultMap="deptEmpResult">
select id,name from dept1
</select>
<select id="getEmpByDid" resultType="employee">
select id,name,did from employee where did = #{did}
</select>