Mybatis官方地址以及相关文件
Mybatis下载地址https://github.com/mybatis/mybatis-3
Mybatis文档地址https://mybatis.org/mybatis-3/
Maven(依赖)
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
mybatis-config.xml文件
<?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 default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/tbatis"/>
<property name="username" value="root"/>
<property name="password" value="xxxxxx"/>
</dataSource>
</environment>
</environments>
<!-- 引入映射配置文件 -->
<mappers>
<!-- 此处注意IDEA创建Resources目录下的文件夹要以com/wcmr/...的方式 -->
<!-- com.wcmr....的方式只是一个目录不是多个目录。所以会造成找不到问题 -->
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
UserMapper.java文件
public interface UserMapper {
// 根据id查询用户所有信息
User selectUserById(int id);
}
Mybatis面向接口编程
- 映射文件的namespace要和mapper接口的全类名保持一致
- 映射文件中SQL语句的id(select id="")要和mapper接口中的方法名保持一致
返回结果Result类型
- ResultType:设置默认的映射关系
- ResultMap:设置自定义的映射关系
public class BaseTest {
@Test
public void testTbatis() throws IOException {
// 加载核心配置文件
InputStream inputStream = getResourceAsStream("mybatis-config.xml");
// 获取SqlSessionFactoryBuilder
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取mapper接口对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 调用UserMapper的实现方法
User user = mapper.selectById(1);
// 打印查询内容
System.out.println(user.toString());
}
}
- SqlSession:代表Java程序和数据库之间的会话(HttpSession是Java程序和浏览器之间的会话)
- SqlSessionFactory:是"生产"SqlSession的"工厂"
- SqlSession默认不提交事务(openSession(false))
Mybatis核心配置文件中,标签的顺序
<configuration>:
<!--标签顺序为: -->
<properties>
<settings>
<typeAliases>
<typeHandlers>
<objectFactory>
<objectWrapperFactory>
<reflectorFactory>
<plugins>
<environments>
<databaseIdProvider>
<mappers>
Mybatis-config.xml标签解释
configuration:
# <configuration>
properties:
# <properties/> 引入properties文件
# resource: 配置文件路径
settings:
# <settings>
setting:
# <setting/>
# name
# value
typeAliases:
# <typeAliases> 设置类型别名
typeAlias:
# <typeAlias /> 设置某个类型的别名
# type:设置需要设置别名的类型
# alias: 设置某个类型的别名,若不设施该属性,那么该类型拥有默认的别名,即类名且不区分大小写
package:
# <package/> 以包为单位,将包下所有的类型设置默认的类型别名,即类名且不区分大小写
# name: 包路径
environments:
environment:
# <environment> 配置某个具体的环境
# id: 表示连接数据库的环境的唯一标识.不能重复
transationManager:
# <transactionManager> 设置事务管理方式
# type: "JDBC/MANAGED"
# JDBC 标识当前环境中,操作SQL时,使用的是JDBC中原生的事务管理方式,事务的提交和回滚需要手动处理
# MANAGED 被管理,例如Spring
dataSource:
# <dataSource> 配置数据源
# type: 设置数据源类型
# type: "POOLED/UNPOOLED/JNDI"
# POOLED 表示使用数据库连接池缓存数据库连接
# UNPOOLED 表示不使用数据库连接池
# JNDI 表示使用上下文的数据源
property:
# <property/> 设置属性
# name: "driver" # 设置连接数据库的驱动
# name: "url" # 设置连接数据库的连接地址
# name: "username" # 设置连接数据库的用户名
# name: "password" #设置连接数据库的密码
mappers:
# <mappers> 引入映射文件
mapper:
# 具体引入某个类型的映射文件
# resource: 文件路径
package:
# 以包为单位引入映射文件
# name: 包路径
### 以包为单位引入的映射文件
# mapper接口所在的包要和映射文件所在的包一致
# mapper接口要和映射文件的名字一致
Mybatis获取参数值的两种方式
- ${}:本质字符串拼接(遇到数据库里需要引号时,需自行加引号)
-
{}:本质占位符赋值
方式1.单参数方式
getUser(String username);
可以通过${}和#{}以任意的名称获取参数值
示例:
select * from t_user username = '${username|xxx}'
select * from t_user username = #{username|xxx}
方式2.多参数方式
getUser(String username, String password, ..);
mybatis-3.x:
mybatis会将这些参数放到一个map集合中,以两种方式进行存储:
以arg0, arg1,...为键,以参数为值
以param1,param2,...为键,以参数为值
示例:
select * from t_user username = '${arg0|param1}' and password = '${arg1|param2}'
select * from t_user username = #{arg0|param1} and password = #{arg1|param2}
### 验证未通过
# mybatis-3.5.9: 可以使用参数名为键,以参数为值
# 示例:
# select * from t_user username = '${username}' and password = '${password}'
# select * from t_user username = #{username} and password = #{password}
方式3.Map方式
getUser(Map<String, Object> map);
当mapper接口方法有多个时,可以手动将这些参数放到map中存储,参数名为键,以参数为值
方式4.以属性的方式
getUser(User user)
可以通过${}和#{}以属性的的方式(getter)访问属性的方式访问属性值
方式5.@Param注解方式
getUser(@Param("username") String username,@Param("password") String password);
mybatis会将这些参数放到一个map集合中,以两种方式进行存储:
以@Param的值为键,以参数为值
以param1,param2,...为键,以参数为值
示例:
select * from t_user username = '${username|param1}' and password = '${password|param2}'
select * from t_user username = #{username|param1} and password = #{password|param2}
Mybatis返回结果接收
- resultType:设置了默认的类型别名,采取类型别名的返回值结果类型也可以 resultType="_int" ---> int、resultType="integer" ----> Integer 类型别名可以参考官方手册https://mybatis.org/mybatis-3/configuration.html#typeAliases
- resultMap:设置自定义映射属性
<resultMap id="AuthMenuResultMap" type="">
<id column="id" property="id"/>
<id column="age" property="age"/>
<association property="" javaType="com.wcmr.domain.auth.AuthMenu">
<id column="name" property="name"/>
<id column="code" property="code"/>
</association>
</resultMap>
<select id="" resultMap="AuthMenuResultMap" parameterType="">
<foreach collection="" item="" index="" open="" separator="" close=""></foreach>
</select>
- 只返回一条数据 可以通过实体类对象接收 可以通过List集合接收 可以通过Map集合接收.
- 查询返回多条数据 可以通过List集合接收 可以通过Map(List<Map<String, Object>>)集合接收 可以在mapper接口的方法上添加@MapKey("")注解,此时就可以将每条数据转换的Map集合作为值,以某个字段的值作为键,放在同一个Map集合中 注意:此时不能通过实体类对象接收否则会抛TooManyResultExceeption异常.
解决字段名和属性名不一致的情况
<!-- 配置Mapper.xml -->
<!-- List<Emp> selectAllEmp(); -->
<!-- e_name 设置别名为eName -->
<select id="selectAllEmp" resultType="Emp">
select eid, e_name eName, age, sex, dbmail from t_emp
</select>
<!-- 配置mybatis-config.xml -->
<!-- 驼峰命名转换,将_映射为驼峰 -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 配置Mapper.xml -->
<resultMap id="empResultMap" type="Emp">
<id property="eid" column="eid"></id>
<result property="eName" column="e_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="dbmail" column="dbmail"></result>
</resultMap>
<!-- List<Emp> selectAllEmp(); -->
<select id="selectAllEmp" resultMap="empResultMap">
select eid, e_name, age, sex, dbmail from t_emp
</select>
<resultMap id="empDeptResult" type="Emp">
<id property="eid" column="eid"></id>
<result property="eName" column="e_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="dbmail" column="dbmail"></result>
<result property="dept.did" column="did"></result>
<result property="dept.dName" column="d_name"></result>
</resultMap>
<!-- List<Emp> selectEmpDept(@Param("eid") Integer eid); -->
<select id="selectEmpDept" resultMap="empDeptResult">
select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid}
</select>
<resultMap id="empDeptResultAss" type="Emp">
<id property="eid" column="eid"></id>
<result property="eName" column="e_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="dbmail" column="dbmail"></result>
<association property="dept" javaType="Dept">
<id property="did" column="did"></id>
<result property="dName" column="d_name"></result>
</association>
</resultMap>
<!-- association 处理多对一映射关系 -->
<!-- property: 需要处理多对的映射关系属性名 -->
<!-- javaTpye: 该属性的类型 -->
<!-- List<Emp> selectEmpDeptAss(@Param("eid") Integer eid); -->
<select id="selectEmpDeptAss" resultMap="empDeptResultAss">
select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid}
</select>
<resultMap id="deptEmpResultMap" type="Dept">
<id property="did" column="did"></id>
<result property="dName" column="d_name"></result>
<collection property="emps" ofType="Emp">
<id property="eid" column="eid"></id>
<result property="eName" column="e_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="dbmail" column="dbmail"></result>
</collection>
</resultMap>
<!-- Dept selectDeptEmp(@Param("did") Integer did); -->
<select id="selectDeptEmp" resultMap="deptEmpResultMap">
select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
</select>
<!-- Dept dept = mapper.selectDeptEmp(1); -->
<!-- DeptMapper.xml -->
<resultMap id="deptEmpResultStepOne" type="Dept">
<id property="did" column="did"></id>
<result property="dName" column="d_name"></result>
<collection property="emps"
select="com.wcmr.tbatis.mapper.EmpMapper.selectDeptAndEmpTwo"
column="did">
</collection>
</resultMap>
<!-- Dept selectDeptEmpStepOne(@Param("did") Integer did); -->
<select id="selectDeptAndEmpStepOne" resultMap="deptEmpResultStepOne">
select * from t_dept where did = #{did}
</select>
<!-- EmpMapper.xml -->
<!-- List<Emp> selectDeptAndEmpTwo(@Param("did") Integer did); -->
<select id="selectDeptAndEmpTwo" resultType="Emp">
select * from t_emp where did = #{did}
</select>
<!-- Dept dept = mapper.selectDeptAndEmpStepOne(1); -->
Mybatis缓存技术
Mybatis一级缓存(默认开启)
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
二级缓存开启的条件:
-
在核心配置文件中,设置全局配置属性cacheEnable="true",默认为true,不需要设置
-
在映射文件中设置标签
-
二级缓存必须在SqlSession关闭或提交之后有效
-
查询的所有数据所转换的实体类类型必须时下按序列化的接口使二级缓存失效的情况
两次查询直接执行任意增删改,会使一级缓存和二级缓存同时失效
Mybatis缓存查询的顺序
- 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接用
- 如果二级缓存没有命中,再查询一级缓存
- 如果一级缓存也没有命中,则直接查询数据库
- SqlSession关闭后,一级缓存中的数据会写入二级缓存
Mapper.xml标签解释
mapper:
# <mapper> 映射文件
# namespace: 要和mapper接口的全类名保持一致
cache:
# <cache /> 开启二级缓存(前提是全局配置中开启了)
# eviction: LRU|FIFO|SOFT|WEAK;缓存回收策略.
# eviction: LRU: 最近最少使用的,移除最长时间不被使用的对象(默认)
# eviction: FIFO: 先进先出;按对象进入缓存的顺序来移除它们
# eviction: SOFT: 软引用;移除基于垃圾回收器状态和软引用规则的对象
# eviction: WEAK: 弱引用;更积极地移除基于垃圾收集器状态和弱引用规则的对象
# flushInterval: 刷新间隔, 单位毫秒(默认不设置.没有刷新间隔,缓存仅仅调用语句时刷新)
# size: 引用数目, 正整数
# readOnly: true|fase;只读.
# readOnly: true:只读缓存;会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改.这提供了很重要的性能优势
# readOnly: false:读写缓存;会返回缓存对象的拷贝(通过序列化).慢,但安全(默认)
resultMap:
# <resultMap> 设置自定义映射关系
# id: 唯一标识,不能重复
# type: 设置映射关系中的实体类类型
id:
# <id> 设置主键的映射关系
# property: 设置映射关系的属性名,必须是type属性所设置的实体类类型中的属性名
# column: 设置映射关系中的字段名,必须是sql语句查询出的字段名
result:
# <result> 设置普通字段的映射关系
# property: 设置映射关系的属性名,必须是type属性所设置的实体类类型中的属性名
# column: 设置映射关系中的字段名,必须是sql语句查询出的字段名
association:
# <association> 处理多对一映射关系
# property: 需要处理多对的映射关系属性名
# javaTpye: 该属性的类型
# select: 设置分步查询的sql的唯一标识(namespace.SQLId或者mapper接口的全类名.方法名)
# column: 设置分步查询的条件
# fetchType: 当开启了全局的延迟加载后,可通过此属性手动控制延迟加载的效果
# fetchType: lazy | eager lazy:延迟加载 eager: 立即加载
id:
# <id> 设置主键的映射关系
# property: 设置映射关系的属性名,必须是type属性所设置的实体类类型中的属性名
# column: 设置映射关系中的字段名,必须是sql语句查询出的字段名
result:
# <result> 设置自定义映射关系
# property: 设置映射关系的属性名,必须是type属性所设置的实体类类型中的属性名
# column: 设置映射关系中的字段名,必须是sql语句查询出的字段名
collection:
# <collection> 处理一对多映射关系
# ofType: 表示该属性所对应的集合中存储数据的类型
sql:
# <sql> 设置sql片段
# id: sql片段id名称,方便后续中对sql片段的引用
select:
# <select> 查询
# id: 唯一标识,要和mapper接口中的方法名保持一致
# resultType: 返回结果类型
# resultMap: 自定义返回值结果映射
if:
# <if> 动态SQL,根据标签中test属性所对应的表达式决定标签中的内容是否需要拼接到SQL中
# test: 判断条件
where:
# <shere> 当where标签有内容时,会自动生成where关键字,并且将内容前多余的and 或or去掉
# <shere> 当where标签没有内容时,此时where没有任何效果
if:
# <if> 动态SQL,根据标签中test属性所对应的表达式决定标签中的内容是否需要拼接到SQL中
# test: 判断条件
trim:
# <trim> 有内容时根据属性添加或去除内容前面或后面的指定内容,当标签中没有内容,trim也没有任何效果
# prefix: 将trim标签中内容前面添加指定内容
# suffix: 将trim标签中内容后面添加指定内容
# prefixOverrides: 将trim标签中内容前面去除指定内容
# suffixOverrides: 将trim标签中内容后面去除指定内容
choose:
# <choose> 配合when和otherwise相当于java中的if...else if...else
when:
# <when> 相当于if,至少有一个
otherwise:
# <otherwise> 相当于else,最多只有一个
include:
# <include> 引用sql
# refid: 引用的id
insert:
# <insert> 修改
# id: 唯一标识,要和mapper接口中的方法名保持一致
# resultType: 返回结果类型
# resultMap: 自定义返回值结果映射
# useGeneratedKeys: 设置当前标签中的sql使用了自增的主键
# keyProperty: 将自增的主键的值赋值给传输到映射文件参数的某个属性
foreach:
# <foreach> 类似for循环
# collection: 设置需要循环的数组或集合
# item: 表示数组和集合中的每一个数据
# separator: 循环体之间的分隔符
# open: foreach标签所循环的所有内容的开始符
# close: foreach标签所循环的所有内容的结束符
delete:
# 删除标签
foreach:
# <foreach> 类似for循环
# collection: 设置需要循环的数组或集合
# item: 表示数组和集合中的每一个数据
# separator: 循环体之间的分隔符
# open: foreach标签所循环的所有内容的开始符
# close: foreach标签所循环的所有内容的结束符