一.简介
Mybatis是一款轻量级持久层的ORM框架
Object Relational Mapping
二.应用搭建
2.1.mybatis-config全局配置文件,数据库db.properties配置文件
2.2.mapper接口以及对于的xml文件
2.3.@Junit测试
2.1.mybatis-config全局配置文件,数据库db.properties配置文件
<?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>
<!-- 指定资源文件 -->
<!-- 参考文档:https://blog.51cto.com/suyanzhu/1916951 -->
<properties resource="db.properties"></properties>
<!-- 开启支持缓存,默认值就是true -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!--环境配置-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${conf.driver}"/>
<property name="url" value="${conf.url}"/>
<property name="username" value="${conf.username}"/>
<property name="password" value="${conf.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--<mapper resource="EmpMapper.xml"/>-->
<mapper class="com.mybatis.wang.mapper.EmpMapper"></mapper>
</mappers>
</configuration>
db.properties配置文件
conf.driver=com.mysql.jdbc.Driver conf.url=jdbc:mysql://localhost:3306/wang_learn conf.username=root conf.password=root
2.2.mapper文件
package com.mybatis.wang.mapper;
import com.mybatis.wang.pojo.Emp;
import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
// @CacheNamespace 注解的方式开启二级缓存
@CacheNamespace
public interface EmpMapper {
public Emp selectEmp(Integer id);
@Select("select * from t_emp where id=${id}")
public Emp selectEmpByAnno$(Integer id);
@Select("select * from t_emp where id=#{id}")
public Emp selectEmpByAnno(Integer id);
@Select("select * from t_emp where id=#{id}")
public List<Emp> selectEmpListByAnno(Integer id);
@Select("select * from t_emp_error where id=#{id}")
public Emp selectEmpByAnnoError(Integer id);
@Select("select * from t_emp where id=#{id} and name=#{name}")
public List<Emp> selectEmpListByMultiParam(@Param("id")Integer id , @Param("name")String name);
@MapKey("id")
public Map<Integer, Emp> getAllEmpReturnMap();
public Emp findEmpByEmpno(Integer empno);
public int updateEmp(Emp emp);
public int deleteEmp(Integer empno);
public int insertEmp(Emp emp);
}
<?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="com.mybatis.wang.mapper.EmpMapper">
<!--<cache></cache>-->
<!--根据id查询Emp实体-->
<select id="selectEmp" resultType="com.mybatis.wang.pojo.Emp">
select * from t_emp where id = #{id}
</select>
<!-- 返回map结果集 -->
<select id="getAllEmpReturnMap" resultType="com.mybatis.wang.pojo.Emp">
select * from `wang_learn`.`t_emp`
</select>
<insert id="insertEmp">
INSERT INTO
`wang_learn`.`t_emp` (`id`, `name`)
VALUES (#{id}, #{name});
</insert>
<update id="updateEmp">
UPDATE `wang_learn`.`t_emp`
SET name=#{name}
WHERE id=#{id}
</update>
<delete id="deleteEmp">
DELETE FROM `wang_learn`.`t_emp`
WHERE id=#{id}
</delete>
</mapper>
注意这里默认情况下mapper.xml文件不会加载到classpath对于的target下面,如果想把接口和mapper文件放在一起,要在pom,xml里面bulid标签中加上如下:
<build>
<!--保证mapper的接口和xml在一起-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
2.3.单元测试
package com.mybatis.wang.test;
import com.mybatis.wang.mapper.EmpMapper;
import com.mybatis.wang.pojo.Emp;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
public class TestEmpCRUD {
SqlSessionFactory sqlSessionFactory;
@Before
public void before(){
// 从 XML 中构建 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
/**
* 基于StatementId的方式去执行SQL
* <mapper resource="EmpMapper.xml"/>
* @throws IOException
*/
@Test
public void test01() {
try (SqlSession session = sqlSessionFactory.openSession()) {
Emp emp = (Emp) session.selectOne("com.mybatis.wang.mapper.EmpMapper.selectEmp", 1);
System.out.println(emp);
}
}
@Test
public void test01_list() {
try (SqlSession session = sqlSessionFactory.openSession()) {
EmpMapper mapper = session.getMapper(EmpMapper.class);
List list = mapper.selectEmpListByAnno(1);// com.mybatis.wang.mapper.EmpMapper.selectEmpListByAnno
System.out.println(list);
List secondQueryList = mapper.selectEmpListByAnno(1);
System.out.println("secondQueryList = " + secondQueryList);
}
}
/**
* 在一个sqlsession里面,连续查询同一个sql二次,参数一致的情况下
*
* 第一次查询库了,第二次走了 一级缓存
* (二级缓存是mapper应用级别,针对多个sqlsession都有效,默认情况下不开启二级缓存)
*/
@Test
public void test01_learnCacheTwo() {
try (SqlSession session = sqlSessionFactory.openSession()) {
EmpMapper mapper = session.getMapper(EmpMapper.class);
Emp firstQuery = mapper.selectEmp(1);// com.mybatis.wang.mapper.EmpMapper.selectEmpListByAnno
System.out.println(firstQuery);
Emp secondQuery = mapper.selectEmp(1);
System.out.println("secondQuery = " + secondQuery);
}
}
@Test
public void test03(){
try (SqlSession session = sqlSessionFactory.openSession()) {
EmpMapper mapper = session.getMapper(EmpMapper.class);
Emp emp = mapper.selectEmpByAnno(2);
System.out.println(emp);
}
}
@Test
public void test04(){
try (SqlSession session = sqlSessionFactory.openSession()) {
EmpMapper mapper = session.getMapper(EmpMapper.class);
Emp emp = mapper.selectEmpByAnnoError(3);
System.out.println(emp);
}
}
/**
* ${} 以字符串拼接的形式形成SQL,会有注入问题
*
* #{} 预编译
*
*/
@Test
public void test05_query$(){
try (SqlSession session = sqlSessionFactory.openSession()) {
EmpMapper mapper = session.getMapper(EmpMapper.class);
Emp emp = mapper.selectEmpByAnno$(3);
System.out.println(emp);
}
}
@Test
public void test05_queryMultiParam(){
try (SqlSession session = sqlSessionFactory.openSession()) {
EmpMapper mapper = session.getMapper(EmpMapper.class);
List<Emp> listByMultiParam = mapper.selectEmpListByMultiParam(10, "test_xiaowang");
System.out.println(listByMultiParam);
}
}
@Test
public void test05_queryEmpReturnMap(){
try (SqlSession session = sqlSessionFactory.openSession()) {
EmpMapper mapper = session.getMapper(EmpMapper.class);
Map<Integer, Emp> allEmpReturnMap = mapper.getAllEmpReturnMap();
System.out.println(allEmpReturnMap);
}
}
@Test
public void test05_Insert(){
try (SqlSession session = sqlSessionFactory.openSession()) {
EmpMapper mapper = session.getMapper(EmpMapper.class);
Emp empPojo = new Emp();
empPojo.setId(11);
empPojo.setName("emp【11】");
int i = mapper.insertEmp(empPojo);
System.out.println("影响行数===========> " + i );
System.out.println("commit提交之前");
session.commit();
}
}
}
三.demo部分结果
四.小结
1.请注意接口和xml文件一致性,都要加载到classpath中
2.一级缓存是基于session级别,二级缓存基于mapper应用级别(默认不开启)
五.源码流程理解
1. 首先会去解析全局配置文件,然后去解析对应的mapper.xml文件,都加载到一个configuration的对象中,然后通过这个configuration去构造SqlSessionFactory。
2. 通过SqlSessionFactory得到Sqlsession对象,这里是通过SqlSession里面的执行器Executor去干活的。(org.apache.ibatis.executor.Executor 种类用途后续详细介绍)
3.一级缓存基于BaseExecutor里面的localCache变量,每次事务的提交和回滚之前都会清空localCache。
二级缓存基于CachingExecutor里面的事务管理缓存tcm对象。
4.关于Cache的理解,它也是一层包裹着一层,其目的是职责单一性。干活是也会逐级委托(delegate.getObject(key))