目录

一、什么是MyBatis

二、Mybatis相对JDBC有哪些优势

三、Mybatis框架的原理介绍

四、Mybatis全局配置文件

1.全局配置文件的类容和顺序

五、映射文件

1.输入映射parameterType

2.resultType结果映射

3.resultMap结果映射

六、Mybatis之传统Dao层的开发(该方式很少用)

1.开发环境准备:

2.需求分析:

3.代码实现

七、Mybatis之Mapper接口的开发方式

1.需求分析

2.Mapper开发代理规范

3.代码实现

​八、Mybatis一级缓存

1.证明一级缓存的存在:

九、Mybatis二级缓存

1.开启二级缓存

2.禁用二级缓存

3.刷新二级缓存

小结:


一、什么是MyBatis

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

相关视频教程在线观看:动力节点MyBatis教程实战精讲(适用于SSM框架初学者课程循序渐进,深入浅出)_哔哩哔哩_bilibili如果你所做的项目业务比较复杂,那么在DAO层可以考虑使用MyBatis框架,MyBatis本是apache的一个开源项目iBATIS,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。https://www.bilibili.com/video/BV185411s7Ry

二、Mybatis相对JDBC有哪些优势

首先我们来看一看jdbc连接数据库的连接方法:


public static void main(String[] args) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {//1、加载数据库驱动Class.forName("com.mysql.jdbc.Driver");//2、通过驱动管理类获取数据库链接connection =  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis", "root", "root");//3、定义sql语句 ?表示占位符String sql = "select * from user where username = ?";//4、获取预处理statementpreparedStatement = connection.prepareStatement(sql);//5、设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值preparedStatement.setString(1, "王五");//6、向数据库发出sql执行查询,查询出结果集resultSet =  preparedStatement.executeQuery();//7、遍历查询结果集while(resultSet.next()){User user System.out.println(resultSet.getString("id")+"  "+resultSet.getString("username"));}} catch (Exception e) {e.printStackTrace();}finally{//8、释放资源if(resultSet!=null){try {resultSet.close();//释放结果集} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(preparedStatement!=null){try {preparedStatement.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(connection!=null){try {connection.close();//关闭数据库连接} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}

通过上面的一段jdbc连接数据代码,我们看有哪些不好的地方:

1.在创建connection的时候,存在硬编码问题(也就是直接把连接信息写死,不方便后期维护)

2.preparedStatement对象在执行sql语句的时候存在硬编码问题。

3.每次在进行一次数据库连接后都会关闭数据库连接,频繁的开启/关闭数据连接影响性能。

简单的说一下mybatis相对jdbc的优势:

1.mybatis是把连接数据库的信息都是写在配置文件中,因此不存在硬编码问题,方便后期维护。

2.mybatis执行的sql语句都是通过配置文件进行配置,不需要写在java代码中。

3.mybatis的连接池管理、缓存管理等让连接数据库和查询数据效率更高。

三、Mybatis框架的原理介绍

这里就通过一张图来对mybatis框架原理进行介绍吧:

四、Mybatis全局配置文件

SqlMapConfig.xml是Mybatis的全局配置文件,它的名称可以是任意,但是一般命名都为(SqlMapConfig)

1.全局配置文件的类容和顺序

  • Properties(属性)
  • Settings(全局参数设置)
  • typeAliases(类型别名)
  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
  • environments(环境信息集合)
  • environment(单个环境信息)
  • transactionManager(事物)
  • dataSource(数据源)
  • mappers(映射器)

2.常见配置详解

properties标签:

Mybatis可以通过该标签来读取java配置信息:

例如在工程中对数据源信息写在db.properties文件中,可以通过properties标签来加载该文件。

db.properties:

db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/mybatis
db.username=root
db.password=12345678

SqlMapConfig.xml使用properties标签:


<!-- 通过properties标签,读取java配置文件的内容 -->
<properties resource="db.properties" /><!-- 配置mybatis的环境信息 -->
<environments default="development"><environment id="development"><!-- 配置JDBC事务控制,由mybatis进行管理 --><transactionManager type="JDBC"></transactionManager><!-- 配置数据源,采用dbcp连接池 --><dataSource type="POOLED"><property name="driver" value="${db.driver}"/><property name="url" value="${db.url}"/><property name="username" value="${db.username}"/><property name="password" value="${db.password}"/></dataSource></environment>
</environments>
  • 先加载properties中property标签声明的属性

因此在property中的name属性的值和value比properties中的resource属性先加载。后加载的db.properties会覆盖于property加载属性和值。

<properties resource="db.properties"><property name="db.username",value="1234"/></properties>
  • 再加载properties标签引入的java配置文件中的属性
  • parameterType的值会和properties的属性值发生冲突。因此,在properties文件里的内容命名最好加上db.代表是跟数据源相关的属性,这样就不容易跟以后的属性发生冲突。

settings标签:
该标签时mybatis的全局设置,该设置会影响mybatis的运行。

一般我们使用使用该标签来开启二级缓存和懒加载。

以下是几张settings配置项的说明:
 

typeAliases标签

该标签是对po类进行别名设置,这样,在后面使用po类的时候就可以直接通过别名引用,而不需要通过po类的全限定名来引用。这样可以提高我们的开发效率。

首先介绍下Mybatis的默认提供的别名有

自定义单个别名:这种方式只能定义单个类的别名。

下面的代码就是把com.lc.mybatis.po.User类定义为user的别名

<typeAliases><!-- 设置单个别名 --><typeAlias type="com.lc.mybatis.po.User" alias="user"/></typeAliases>

自定义之批量定义别名:

下面代码是把com.lc.mybatis.po类下的所有类都声明别名,默认的别名就是类名(类名大小写都可以)


<!-- 设置别名 --><typeAliases><!-- 批量设置别名 --><!-- package:指定包名称来为该包下的po类声明别名,默认的别名就是类名(类名首字母大小写都可以) --><package name="com.lc.mybatis.po"/></typeAliases>

mappers标签

该标签的作用是加载映射文件

方式一:<mapper resource=""/>

该方式是加载相对于类路径下的映射文件:


<mappers><mapper resource="sqlmap/User.xml"/>
</mappers>

方式二:<mapper url=""/>

该方式使用全限定路径

方式三:<mapper class=""/>

该方式使用mapper接口的全限定类名

此方式要求:

Mapper接口Mapper映射文件名称相同且在同一个目录下。

方式四:<package name=""/>

该方式是加载指定包下的所有映射文件

此方式要求:

Mapper接口Mapper映射文件名称相同且在同一个目录下。

五、映射文件

1.输入映射parameterType

第一种:简单类型

#{}表示占位符?,parameterType接收简单类型的参数时,里面的名称可以任意


<select id="findUserById" parameterType="java.lang.Integer" resultType="user">SELECT * FROM USER WHERE id = #{id}</select>

${}表示拼接符,parameterType接收简单类型的参数时,里面的名称必须是value

<select id="findUsersByName" parameterType="java.lang.String" resultType="com.lc.mybatis.po.User">SELECT * FROM USER WHERE username LIKE "%${value}%"</select>

第二种:pojo类型

这里通过用户的用户名进行模糊查询演示pojo类型

在映射文件中添加模糊查询语句:

<!-- parameterType传递pojo类型 --><select id="findUsersByPojo" parameterType="com.lc.mybatis.po.User" resultType="com.lc.mybatis.po.User">SELECT  * FROM USER WHERE username LIKE "%${username}%"</select>

user类

public class User {private Integer id;private String username;private Date birthday;private String sex;private String address;
}

测试类


public class UserDao{
//根据用户名进行模糊查询@Overridepublic List<User> findUserByPojo(){ //全局配置文件路径:String resource = "SqlMapConfig.xml";InputStream inputStream = Resources.getResourceAsStream(resource);//创建SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();User user = new User();user.setUsetname("张三");List<User> users = (List<User>)sqlSession.selectList("test.findUsersByPojo",user);//传入pojoSystem.out.println(users);sqlSession.close();return users;}
}

第三种:包装类型pojo

这里通过用户名和用户地址对用户进行查询来演示包装类型pojo:

首先创建包装pojo类:


public class UserVO {private User user;public User getUser() {return user;}public void setUser(User user) {this.user = user;}}

在映射文件中添加查询语句:

<!-- parameterType传递pojo包装类型 --><select id="findUsersByPojo1" parameterType="com.lc.mybatis.po.UserVO" resultType="user"> SELECT * FROM USER WHERE username LIKE "%${user.username}%" AND address=#{user.address}</select>

测试类


public class UserDao{
//根据用户名和地址进行查询@Overridepublic List<User> findUserByPojo1(){//全局配置文件路径:String resource = "SqlMapConfig.xml";InputStream inputStream = Resources.getResourceAsStream(resource);//创建SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();User user = new User();user.setUsetname("张三");user.setAddress("郝汉山");UserVO userVo = new UserVO();userVo.setUser(user);List<User> users = (List<User>)sqlSession.selectList("test.findUsersByPojo1",userVo);//传入pojo包装类System.out.println(users);sqlSession.close();return users;}}

第四种:map集合类型

这里通过查询用户信息演示:

在映射文件中添加该查询语句:


<!-- parameterType传递hashmap类型 --><select id="findUsersByMap" parameterType="java.util.Map" resultType="user">SELECT * FROM USER WHERE username LIKE "%${username}%" AND address=#{address}</select>

测试方法

public class UserDao{
//根据用户名和地址进行查询@Overridepublic List<User> findUserByMap(){//全局配置文件路径:String resource = "SqlMapConfig.xml";InputStream inputStream = Resources.getResourceAsStream(resource);//创建SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();Map<String,String> map = new HashMap<>();map.put("username","张三");map.put("address","郝汉山");List<User> users = (List<User>) sqlSession.selectList("test.findUsersByMap",map);//传入pojo包装类System.out.println(users);sqlSession.close();return users;}}

2.resultType结果映射

resultType结果映射要求:需要查询结果的列名和映射的对象的属性名一致,这样才能映射成功。如果映射没成功也不会报错,只是映射结果中对象的相应属性没有值,为空。如果映射的列名和对象中的属性名全部不一致,那么映射的对象为空。如果在使用sql语句查询的时候给查询结果列设置了别名,则别名要和映射结果对象的属性名一致,这样才能保证映射成功。

第一种:简单类型

注意: 如果结果映射为简单类型,则需要查询的结果为一列才能映射成功。

例如:查询用户表中用户的总数。

映射文件为:


<!-- resultType:输出为简单类型 --><select id="findUserCount" resultType="int">select count(*) from user;</select>

测试代码:

public class UserDao{@Overridepublic int findUserCount(){//全局配置文件路径:String resource = "SqlMapConfig.xml";InputStream inputStream = Resources.getResourceAsStream(resource);//创建SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();int userCount= sqlSession.selectOne("test.findUserCount");System.out.println(userCount);sqlSession.close();return userCount;}}

第二种:pojo结果映射

这里操作pojo输入映射。

3.resultMap结果映射

使用resultMap结果映射时,不需要查询出来的结果集的列名和映射结果对象的属性名相同,但是需要声明一个resultMap,手动的方式来对列名和对象属性进行映射。(resultMap一般用于多表关联映射)

例如:通过查询用户表中的用户,并对查询出来的用户表的列名设置别名。

映射文件添加查询语句:

[id]:定义resultMap的唯一标识

[type]:定义该resultMap最终映射的pojo对象

[id标签]:映射结果集的唯一标识列,如果是多个字段联合唯一,则定义多个id标签

[result标签]:映射结果集的普通列

[column]:SQL查询的列名,如果列有别名,则该处填写别名

[property]:pojo对象的属性名

<!-- 如果查询出来的列名有别名就不能通过resultType来接收输出类型了。需要通过resultMap来声明传出类型(resultMap需要声明) --><resultMap type="user" id="userMap"><!-- id标签:专门查询结果中唯一列映射 --><id column="id_" property="id"/><!-- result标签:映射查询结果中的普通列 --><result column="username_" property="username"/><result column="address_" property="address"/></resultMap><select id="findUserResultMap" parameterType="int" resultMap="userMap">select id id_,username username_,address address_ from user where id=#{id}</select>

测试类:

public class UserDao{@Overridepublic User findUserResultMap(){//全局配置文件路径:String resource = "SqlMapConfig.xml";InputStream inputStream = Resources.getResourceAsStream(resource);//创建SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();User user = sqlSession.selectOne("test.findUserResultMap",1);System.out.println(user);sqlSession.close();return user;}}

4.动态sql
在mybatis中提供了一些动态sql标签,可以让我们开发效率更快,这些动态sql语句可以增加我们写的sql语句的重用性,常用的动态sql语句标签有:if标签、sql片段(需要先定义后使用)、where标签、foreach标签

通过下面例子来演示动态sql常用的标签:

需求分析:查询用户表中相关的用户。

发出相关的sq语句有:select * from user where username like "%张三%" and address= ?;

select * from user;

select * from user where id in(1,2,10);

如何才能让这些语句在我们需要的时候就使用,不需要的时候就不适用。其实我们发现这三条语句有很多重复的地方,我们如果能做到让重复的能够重复使用,没有重复的可以按我们需求使用的话就能减少我们写很多sql语句。当然动态sql就是帮我们解决这些问题的。

映射文件:

<!-- 定义sql片段,用于可重用的sql片段 --><sql id="whereClause"><!-- if标签:可以对输入的参数进行判断 --><!-- test:指定判断表达式 --><if test="user!=null"><if test="user.username!=null and user.username!=''">AND username LIKE '%${user.username}%'</if><if test="user.address!=null and user.address!=''">AND address=#{user.address}</if></if><if test="idList!=null">AND id IN<!-- foreach标签: 可以循环传入参数值 --><!-- collenction:标示pojo中集合属性的属性名称 --><!-- item:每次遍历出来的对象 --><!--open开始遍历时拼接的串--><!--close结束遍历时拼接的串--><!--separator遍历每个对象之间需要拼接字符--><foreach collection="idList" item="item" open="(" close=")" separator=",">#{item}</foreach></if></sql><select id="findUserList" parameterType="userVO" resultType="user">SELECT * FROM USER<!-- where标签: 默认去掉第一个AND,如果没有参数就去掉where自己--><where><!--引用sql语句片段--><include refid="whereClause"></include></where></select>

userVo类:

public class UserVO {private User user;private List<Integer> idList;public List<Integer> getIdList() {return idList;}public void setIdList(List<Integer> idList) {this.idList = idList;}public User getUser() {return user;}public void setUser(User user) {this.user = user;}}

测试类:


public class UserDao{@Overridepublic void findUserList(){//全局配置文件路径:String resource = "SqlMapConfig.xml";InputStream inputStream = Resources.getResourceAsStream(resource);//创建SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();//测试foreach语句执行UserVO userVo = new UserVO();List<Integer> idList = new ArrayList<>();idList.add(1);idList.add(2);idList.add(3);userVo.setIdList(idList);//测试select * from user where username like ? and address=?;//User user = new User();//user.setUsername("张三");//user.setAddress("武当山");//userVo.setUser(user);List<User> users = sqlSession.selectOne("test.findUserList",userVo);System.out.println(users);sqlSession.close(); }}

六、Mybatis之传统Dao层的开发(该方式很少用)

1.开发环境准备:

  • 个人使用的jdk为1.7
  • 开发工具是使用的Eclipse4.5
  • 数据库使用的MySQL5X
  • 导入mybatis所需要的jar包

  • 导入mysql数据库驱动包

2.需求分析:

根据ID查询查询用户、根据用户名称进行模糊查询、添加用户

3.代码实现

创建用户表对应pojo类User:


public class User {private Integer id;private String username;private Date birthday;private String sex;private String address;//setter和get方法省略
}

创建mybatis的全局配置文件SqlMapConfig.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><!-- 配置mybatis的环境信息 --><environments default="developments"><environment id="developments"><!-- 配置JDBC事务控制,由mybatis进行管理 --><transactionManager type="JDBC"></transactionManager><!-- 配置数据源,采用mybatis连接池 --><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis"/><property name="username" value="root"/><property name="password" value="12345678"/></dataSource></environment></environments><!-- 加载映射文件 --><mappers><mapper resource="User.xml"/></mappers>
</configuration>

创建需求开发的映射文件User.xml配置文件:并在全局配置文件中添加该映射文件

<?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">
<!-- namespace:命名空间,它的作用就是对SQL进行分类化管理,可以理解为SQL隔离注意:使用mapper代理开发时,namespace有特殊且重要的作用-->
<mapper namespace="test"><!-- 根据用户ID查询用户信息 --><!-- select:表示一个MappedStatement对象 --><!-- id:statement的唯一标识 --><!--  #{}:表示一个占位符?--><!-- #{id}:里面的id表示输入参数的参数名称,如果该参数为简单类型,那么#{}里面的参数可以任意 --><!-- parameterType:输入参数的java类型 --><!-- resultType:输出结果的所映射的java类型(单条结果所对应的java类型) --><select id="findUserById" parameterType="java.lang.Integer" resultType="com.lc.mybatis.po.User">SELECT * FROM USER WHERE id = #{id}</select><!-- 根据用户名进行模糊查询 --><!-- ${}:表示一个sql连接符 --><!-- ${value}:里面的 value表示输入的名称,如果该参数是简单类型,那么${}里面的参数名称必须是value--><!-- ${}这种写法存在sql注入的风险,所以需要 慎用!但是有些场景需要用到比如:排序,--><select id="findUsersByName" parameterType="java.lang.String" resultType="com.lc.mybatis.po.User">SELECT * FROM USER WHERE username LIKE "%${value}%"</select><!-- 添加用户: --><!-- [selectKey标签]:通过select查询来生成主键[keyProperty]:指定存放生成主键的属性[resultType]:生成主键所对应的Java类型[order]:指定该查询主键SQL语句的执行顺序,相对于insert语句[last_insert_id]:MySQL的函数,要配合insert语句一起使用,该函数在mysql中是执行在insert语句后。--><insert id="insertUser" parameterType="com.lc.mybatis.po.User"><selectKey keyProperty="id" resultType="int" order="AFTER">SELECT LAST_INSERT_ID()</selectKey>INSERT INTO USER(username,sex,birthday,address) VALUES(#{username},#{sex},#{birthday},#{address})</insert>
</mapper>

dao层接口:

public interface UserDao {//根据用户id查询用户public User findUserById(int id);//根据用户名进行模糊查询public List<User> findUsersByName(String name);//添加用户public void addUser(User user);}

dao层的实现:

public class UserDaoImpl implements UserDao{//通过构造方法注入sqlSessionFactoryprivate SqlSessionFactory sqlSessionFactory;public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory = sqlSessionFactory;}//根据id查询用户@Overridepublic User findUserById(int id) {SqlSession sqlSession = sqlSessionFactory.openSession();User user = sqlSession.selectOne("test.findUserById", id);System.out.println(user);sqlSession.close();return user;}//根据用户名进行模糊查询@Overridepublic List<User> findUsersByName(String name){SqlSession sqlSession = sqlSessionFactory.openSession();List<User> users = sqlSession.selectList("test.findUsersByName",name);System.out.println(users);sqlSession.close();return users;}//添加用户public List<User> addUser(String name){SqlSession sqlSession = sqlSessionFactory.openSession();User user = new User();user.setUsername("超哥2");user.setAddress("成都市");//调用SqlSession的增删改查方法//第一个参数:表示statement的唯一表示//第一个参数:表示占位符的sqlSession.insert("test.insertUser", user);System.out.println(user.getId());//切记:增删改操作需要提交事务。sqlSession.commit();//关闭资源sqlSession.close();}

测试类:这里就只通过根据id查找用户进行测试


public class UserDaoTest {private SqlSessionFactory sqlSessionFactory;@Beforepublic void setUp() throws IOException {InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void testFindUserById() {UserDao userDao = new UserDaoImpl(sqlSessionFactory);userDao.findUserById(1);}}

七、Mybatis之Mapper接口的开发方式

该方式开发,不需要写dao层的实现类,而是mybatis根据映射文件等信息对接口进行jdk动态代理生成代理类来实现接口中的方法,因此,采用这种方式,我们只需要编辑接口,而不需要去写实现。

1.需求分析

根据id查询用户。

2.Mapper开发代理规范

  • mapper接口的全限定名要和mapper映射文件的namespace值一致。
  • mapper接口的方法名称要和mapper映射文件的statement的id一致。
  • mapper接口的方法参数类型要和mapper映射文件的statement的parameterType的值一致,而且它的参数是一个。
  • mapper接口的方法返回值类型要和mapper映射文件的statement的resultType的值一致。

3.代码实现

准备po类:

public class User {private Integer id;private String username;private Date birthday;private String sex;private String address;//getter和setter方法省略}

Mapper接口:

public interface UserMapper {public User findUserById(int id);
}

UserMapper.xml配置文件:


<?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">
<!-- namespace:命名空间,它的作用就是对SQL进行分类化管理,可以理解为SQL隔离注意:使用mapper代理开发时,namespace有特殊且重要的作用-->
<mapper namespace="com.lc.mybatis.mapper.UserMapper"><!-- 根据用户ID查询用户信息 --><!-- select:表示一个MappedStatement对象 --><!-- id:statement的唯一标识 --><!--  #{}:表示一个占位符?--><!-- #{id}:里面的id表示输入参数的参数名称,如果该参数为简单类型,那么#{}里面的参数可以任意 --><!-- parameterType:输入参数的java类型 --><!-- resultType:输出结果的所映射的java类型(单条结果所对应的java类型) --><select id="findUserById" parameterType="java.lang.Integer" resultType="com.lc.mybatis.po.User">SELECT * FROM USER WHERE id = #{id}</select>
</mapper>

在全局配置文件SqlMapperConfig中添加该映射文件

测试代码:


public class UserMapperTest {private SqlSessionFactory sqlSessionFactory ;@Beforepublic void setUp() throws IOException {InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void testFindUserById() {SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理类UserMapper userMapper = sqlSession.getMapper(UserMapper.class);User user = userMapper.findUserById(10);System.out.println(user);sqlSession.close();}}

八、Mybatis一级缓存

mybatis提供查询缓存,如果缓存中有数据,就不用从数据库中获取,用于减轻数据压力,提高系统性能

一级缓存是sqlSession级别的缓存,在操作数据库的时候,需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的SqlSession的缓存区域(HashMap)是互相不受影响的。

mybatis默认是支持一级缓存的。

1.证明一级缓存的存在:

验证方法:


public void testOneLevelCache() {SqlSession sqlSession = sqlSessionFactory.openSession();//获取UserMapper的代理类UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//第一次查询User user = userMapper.findUserById(10);System.out.println(user);//第二次查询User user2 = userMapper.findUserById(10);System.out.println(user2);sqlSes

通过执行该方法,查看打印日志可以看出就执行了一次sql语句的查询,因此可以判断第二次查询是没有从数据库中进行查询的。

那当什么时候一级缓存会被清空呢?

通过测试发现,当在第二次查询数据库之前对数据库进行了写的操作后,第二次查询就不会从缓存中查询结果,而是直接从数据中查询结果。另一种就是在第一查询结果后,手动的方式清空一级缓存(使用sqlSession.clearCache();方法。)

测试方法:

九、Mybatis二级缓存

二级缓存是Mapper级别的缓存。多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是夸SqlSession的。(二级缓存Mybatis默认是关闭的,需要自己去手动配置开启或可以自己选择用哪个厂家的缓存来作为二级缓存)

1.开启二级缓存

首先在全局配置文件中配置开启二级缓存功能:

<!-- 开启二级缓存总开关 -->
<setting name="cacheEnabled" value="true"/>

在映射文件中去选择是否该映射文件使用二级缓存:

如果使用就进行以下配置,如果不是用,就不需要对映射文件做任何修改。

<!-- 开启本mapper下的namespace的二级缓存,默认使用的是mybatis提供的PerpetualCache -->
<cache></cache>

也可以设置选择二级缓存提工商

以下是我选择使用EhcacheCache缓存(注意:在使用EhcacheCache缓存需要导入jar包)

验证二级缓存是否开启:

验证方法如下:

@Test//测试二级缓存是否开启public void testTwoLevelCache() {SqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();SqlSession sqlSession3 = sqlSessionFactory.openSession();//获取UserMapper的代理类UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);User user1 = userMapper1.findUserById(10);System.out.println(user1);//当sqlSession1执行close()的时候,才把sqlSession1查询的结果写到二级缓存中去。sqlSession1.close();//        User u = new User();
//      u.setUsername("小胖");
//      u.setAddress("成都");
//      u.setSex("2");
//      u.setBirthday(new Date());
//      userMapper3.insertUser(u);
//      //当其中任何一个sqlSession执行commit()方法后将刷新整个缓存区
//      sqlSession3.commit();
//      sqlSession3.close();//第二次查询User user2 = userMapper2.findUserById(10);System.out.println(user2);sqlSession2.close();}

测试结果:

同时通过测试,当在第二次查询的时候,向数据库提交数据后,就会对缓存进行刷新,这样在第二次查询的时候就没有走缓存,而是走的数据库。

2.禁用二级缓存

由于二级缓存默认是关闭的,如果不开启就不会使用二级缓存。如果,我们开启了二级缓存,而在有些查询结果集中,不需要受到二级缓存影响,该怎么去做呢?

在select查询中,默认是使用了二级缓存,如果不想使用二级缓存,就在select标签中有一个useCache的属性设置为false,就代表不使用二级缓存,每次进行查询数据都不会从缓存总获取,而是直接从数据库中进行查询。useCache的默认值是true,即代表statement使用二级缓存。

3.刷新二级缓存

在statement中设置flushCache=true,可以刷新二级缓存。默认情况下,select语句中的flushCache是false。如果是insert、update、delete语句,那么flushCache的默认值是true。如果将select语句中的flushCache值改为true,就意味着查询语句的二级缓存失效,每次查询都会从数据库进行查询。如果将select语句的flushCache值为false,就代表该查询语句使用了二级缓存,如果在数据库中修改了数据,而二级缓存中的数据还是原来的数据,那么这样就会出现脏读。

flushCache设置如下:

小结:

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中;
  • 只有当会话提交,或者关闭的时候,才会提交到二级缓冲中!

【MyBatis教程】mybatis框架超全面详解总结相关推荐

  1. Mybatis持久层框架MBGExample类详解

    Mybatis 1. 概念 1.1 什么是Mybatis 是一个持久层框架: 所谓持久层,也就是数据访问层.又称为DAL层,有时候也称为是持久层,其功能主要是负责数据库的访问. 我的理解就是Mybai ...

  2. 深入浅出Mybatis系列(四)---配置详解之typeAliases别名(mybatis源码篇)

    上篇文章<深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)> 介绍了properties与environments, ...

  3. mysql在xml中jdbctype,MyBatis中的JdbcType映射使用详解

    Java项目涉及到数据库交互,以往常用的是JDBC,现在则有Hibernate.Mybatis等这些持久化支持. 项目中用到了MyBatis,和JDBC最显著的区别,就是SQL语句配置化,通过xml文 ...

  4. spring框架 AOP核心详解

    AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...

  5. ExtJS 4.2 教程-08:布局系统详解

    ExtJS 4.2 系列教程导航目录: ExtJS 4.2 教程-01:Hello ExtJS ExtJS 4.2 教程-02:bootstrap.js 工作方式 ExtJS 4.2 教程-03:使用 ...

  6. pythonmessage用法_django 消息框架 message使用详解

    前言 在网页应用中,我们经常需要在处理完表单或其它类型的用户输入后,显示一个通知信息给用户. 对于这个需求,Django提供了基于Cookie或者会话的消息框架messages,无论是匿名用户还是认证 ...

  7. 定时任务框架APScheduler学习详解

    定时任务框架APScheduler学习详解 APScheduler简介 在平常的工作中几乎有一半的功能模块都需要定时任务来推动,例如项目中有一个定时统计程序,定时爬出网站的URL程序,定时检测钓鱼网站 ...

  8. java集合框架的结构_集合框架(Collections Framework)详解及代码示例

    简介 集合和数组的区别: 数组存储基础数据类型,且每一个数组都只能存储一种数据类型的数据,空间不可变. 集合存储对象,一个集合中可以存储多种类型的对象.空间可变. 严格地说,集合是存储对象的引用,每个 ...

  9. Android系统(96)---Android 数据交换解析框架Gson使用详解

    Android 数据交换解析框架Gson使用详解 Json 是一种文本形式的数据交换格式,比 xml 更为轻量.Json 的解析和生成的方式很多,在 Android 平台上最常用的类库有 Gson 和 ...

最新文章

  1. Java 实现 HTTP 请求的三种方式
  2. Codeforces 1375H Set Merging (分块)
  3. ASP.NET Core 开发-Entity Framework (EF) Core 1.0 Database First
  4. android socket 服务端,Android socket 服务端
  5. C语言弧长,在C ++中从给定角度的弧长?
  6. java 打印hashmap值_HashMap中输出key-value值得方法
  7. android 传感器 应用,Android移动设备中传感器的应用
  8. tracepro应用实例详解_十大行业气动设备 120个典型气动系统应用实例
  9. 97. ExtJS之EditorGridPanel afteredit属性
  10. 初学者怎么快速学习3D建模?零基础必备建模知识,你都明白吗?
  11. 什么是线速路由器 线速转发
  12. AD域中如何批量导入导出账号
  13. 奔三之际,任性一把 ——从华为南研所裸辞后的一些体会和感想
  14. 【新闻推荐系统】(task1)系统搭建基本流程
  15. add-migration 多个DbContext
  16. android:sharedUserId=android.uid.system 的使用
  17. Unity打造简易的GalGame游戏剧本编辑引擎
  18. 95epay支付通道种类:3D通道,实时非3D通道,高级延时非3D通道,高级实
  19. java 时区 edt_时区EST与EST5EDT有何不同?
  20. 表弟问我:自学python可以做什么兼职?

热门文章

  1. Spring Boot Validation
  2. 添加页面填写完必填字段报错
  3. 《Towards Viewpoint Invariant 3D Human Pose Estimation》--深度图领域人体姿态估计的CNN算法
  4. 使用 Nginx 实现 HTTPS 网站设置
  5. c语言分支结构程序设计课件,C语言 分支结构程序设计.ppt
  6. NOIP2010提高组题解
  7. 第2章第22节:如何在SwiftUI中绘制一个圆形 [SwiftUI快速入门到实战]
  8. C#快速入门(vs安装和环境配置)
  9. 安装grub引导的ttylinux
  10. 对favicon进行base64 编码?