Mybatis基础

1. 什么是mybatis

MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

2. mybatis入门

项目地址:https://github.com/zhongyushi-git/spring-collection.git。下载代码后,示例代码在mybatis-demo文件夹下。本项目是以原生的jar方式介绍的,同步的maven版本的代码见https://www.cnblogs.com/zys2019/p/14538018.html

2.1入门案例

第一步:先创建一个普通的ava工程

第二步:在根目录下新建一个lib目录

第三步:导入以下jar包

 第四步:在src下新建config目录,创建db.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db2020?characterEncoding=utf-8
jdbc.username=root
jdbc.password=zys123456

第四步:新建pojo实体类

package com.entity;

public class User {
    private int id;
    private String username;
    private String password;
//get和set,toString方法在此略,使用时需要生成
}

第五步:创建一个接口用于访问数据库

package com.zxh.dao;

import com.zxh.entity.User;

import java.util.List;

public interface UserDao {
List<User> findAll();
}

接口中的方法要和select的id相同。

第六步:在src下新建mapper文件夹,在mapper下新建一个UserDao.xml文件:

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.UserDao">
    <!--查询所有信息
        id是这个select的唯一标识
        resultType是返回类型
        parameterType是参数类型
    -->
    <select id="findAll" resultType="com.dao.User">
        select * from user
    </select>
</mapper>

第七步:在config目录下新建配置文件SqlMapConfig.xml

<?xml version="1.0" encoding="uTF-8" ?>
<!-- mybatis核心配置 -->
<!-- 导入约束的路径 -->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 配置信息 -->
<configuration>
<!-- 引入并加载外部文件 -->
<properties resource="config/db.properties"></properties>
<!-- 给类取别名 -->
<typeAliases>
<!-- 使用包扫描方式取别名 -->
<package name="com.zxh.entity"/>
</typeAliases>
<!-- 环境配置的集合 -->
<environments default="mysql">
<environment id="mysql">
<!-- 事务管理:type指定事务的管理方式,jdbc:交给jdbc管理,MANAGED:被管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据库配置:type是否使用连接池,POOLED:使用连接池,UNPOOLED:不使用连接池 -->
<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>

<!-- 加载映射文件 -->
<mappers>
<!-- 单独加载映射文件-->
<mapper resource="mapper/UserDao.xml"></mapper>
</mappers>
</configuration>

第八步:编写测试类

package com.zxh.test;

import com.zxh.dao.UserDao;
import com.zxh.entity.User;
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.Test;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

public class MyTest {
@Test
public void findAll() throws IOException {
//加载核心配置文件
Reader reader = Resources.getResourceAsReader("config/SqlMapConfig.xml");
//创建SessionFactory
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(reader);
//创建一个session对象
SqlSession session = build.openSession();

UserDao userMapper = session.getMapper(UserDao.class);
List<User> list = userMapper.findAll();
System.out.println(list);
}
}

第八步:执行sql脚本

create database db2020;
CREATE TABLE user (
  id int(11) NOT NULL,
  username varchar(255) DEFAULT NULL,
  password varchar(255) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user values(1,'admin','123');
insert into user values(2,'zhnagsan','456789');
insert into user values(3,'zxh','zxh');

第九步:测试。运行测试方法,在控制台打印了查询的结果。

2.2配置日志文件

已经导入了log4j的jar,主要是在这里使用。

1)在src新建一个log4j.properties文件,配置如下:

### 设置当前日志级别 ###
log4j.rootLogger = debug,stdout,D,E

### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到=E://logs/log.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

需要注意的是,此文件名必须是log4j.properties,另外位置必须放在资源目录下(src根目录)。

2)在测试类中创建日志对象,把信息写到日志文件中,方便查阅:

//创建日志对象
Logger logger = Logger.getLogger(MyTest.class);

3)在查询的方法中添加一个日志的输出

logger.info("我是日志信息");

再次测试会在控制台输出一些日志,这句代码放在类中方法之前,debug信息会自动写到文件中,error信息要在发生异常的地方手动添加。

2.3自定义文件

每次创建xml都比较麻烦,可以自定义一个xml文件,使用起来方便点。操作如下图:

 

3. mybatis的增删改查

3.1方法优化

由于会重复的SqlSessionFactory对象,因此可以把其提取出来,在类加载时就初始化,提高代码复用性。因此,在测试类添加如下代码:

public SqlSessionFactory build = null;

//这个在方法加载的时候就会初始化
@Before
public void before() {
Reader reader = null;
//加载核心配置文件
try {
reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//创建SessionFactory
build = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}

3.2根据id查询

1)在userDao接口添加方法

User findById(Integer id);

2)在UserDao.xml中添加方法

<!-- 如果参数是简单数据类型,可以省略 -->
<select id="findById" parameterType="int" resultType="User">
    select * from user where id=#{id}
</select>

3)新建测试方法

@Test
public void findById() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = userMapper.findById(2);
System.out.println(user);
}

查询所有的方法在入门案例已介绍,在此略。

3.3根据用户名和密码查询

1)在userDao接口添加方法

User findByNmAndPwd(User user);

2)在UserDao.xml中添加方法

<select id="findByNmAndPwd" parameterType="User" resultType="User">
    select * from user where username=#{username} and password=#{password}
</select>

#{ }里面的参数一定要和对象中的属性保持一致

3)新建测试方法

@Test
public void findByNmAndPwd(){
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user=new User();
user.setUsername("admin");
user.setPassword("123");
User user2 = userMapper.findByNmAndPwd(user);
System.out.println(user2);
}

3.4添加用户

1)在userDao接口添加方法

int addUser(User user);

2)在UserDao.xml中添加方法

<insert id="addUser" parameterType="User">
    insert  into user values(null,#{username},#{password})
</insert>

3)新建测试方法

@Test
public void addUser() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = new User();
user.setUsername("方启豪5号");
user.setPassword("12315");
int i = userMapper.addUser(user);
session.commit();//提交事务
System.out.println(i);
}

增加、修改、删除修改一定要提交事务

3.5修改用户

1)在userDao接口添加方法

int updateUser(User user);

2)在UserDao.xml中添加方法

<update id="updateUser" parameterType="User">
update user set username=#{username},password=#{password} where id=#{id}
</update>

3)新建测试方法

@Test
public void updateUser() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = new User();
user.setId(10);
user.setUsername("方启豪2号");
user.setPassword("123");
userMapper.updateUser(user);
session.commit();
}

3.6删除用户

1)在userDao接口添加方法

int deleteUser(Integer id);

2)在UserDao.xml中添加方法

<delete id="deleteUser">
   delete from user where id=#{value}
</delete>

3)新建测试方法

@Test
public void deleteUser() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
userMapper.deleteUser(10);
session.commit();
}

3.7模糊查询:一个条件

一个条件的模糊查询是特例,使用${},并且括号里面只能写value,这里参数是简单数据类型

1)在userDao接口添加方法

List<User> findByLikeOne(String username);

2)在UserDao.xml中添加方法

<!-- 模糊查询:一个条件,使用${},并且括号里面只能写value -->
<select id="findByLikeOne" resultType="User">
    select * from user where username like '%${value}%'
</select>

3)新建测试方法

@Test
public void findByLikeOne() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
List<User> list = userMapper.findByLikeOne("h");
System.out.println(list);
}

3.8模糊查询:多个条件

使用${},并且括号里面要与对象的属性相同。

1)在userDao接口添加方法

List<User> findByLikeMore(User user);

2)在UserDao.xml中添加方法

<!-- 模糊查询:多个条件,使用${},并且括号里面要与对象的属性相同 -->
<select id="findByLikeMore" parameterType="User" resultType="User">
    select * from user where username like '%${username}%' and password like '%${password}%'
</select>

3)新建测试方法

@Test
public void findByLikeMore() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = new User();
user.setUsername("h");
user.setPassword("4");
List<User> list = userMapper.findByLikeMore(user);
System.out.println(list);
}

4. 章中小结

4.1#{}和${}的区别

(1)#{}

1)表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,可以有效防止sql注入。

2)可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

(2)${}

1)表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换

2) ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

4.2parameterType和resultType

parameterType:指定输入参数类型

resultType:指定输出结果类型

4.3mybatis与hibernate的区别

Mybatis是对jdbc的封装,注重的是sql语句,是一种轻量级的半自动框架,适用于敏捷开发,原理是反射

Hibernate注重映射关系,是一种重量级的全自动的框架。

4.4取别名typeAliases

1)mybatis支持别名,映射关系如下表:

别名 映射的类型 别名 映射的类型
_byte byte string string
_long long byte byte
_short short long long
_int int short short
_integer int int int
_double double integer Integer
_float float double Double
_boolean boolean float Float
decimal BigDecimal boolean Boolean
bigdecimal BigDecimal map Map

2)自定义别名方法

在SqlMapConfig.xml中配置:

<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="com.entity.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="com.entity"/>
<package name="其它包"/>
</typeAliases>

可以配置单个别名,也可以直接扫描整个包,建议使用第二种方式。

4.6mappers(映射器)

Mapper配置的几种方法:

代码 说明 示例 备注
<mapper resource=" " /> 使用相对于类路径的资源 <mapper resource="sqlmap/User.xml" />  
<mapper class=" " /> 使用mapper接口类路径 <mapper class="com.mapper.UserMapper"/> 要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
<package name=""/> 注册指定包下的所有mapper接口 <package name="com.mapper"/> 要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中

4.7 dao接口开发规范

只需要编写Mapper接口,非常适用于mybatis,Mapper接口开发需要遵循以下规范,代码在入门中已说明这些:

1、Mapper.xml文件中的namespace与mapper接口的路径相同。

2、Mapper接口方法名和Mapper.xml中定义的每个statement的id相同

3、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同

4、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

5.resultMap与parameterMap

5.1复杂条件的查询举例

当参数不属于同一个对象时,使用简单的查询非常麻烦,那么可以把一个对象作为另一个对象的属性结合使用,示例如下。

1)新建三个实体类

Person类

package com.zxh.entity;

public class Person {
private String username;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}
}

People类

package com.zxh.entity;

public class People {
  private String password;

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

PVo类:把上面的两个对象作为属性给PVo

package com.zxh.entity;

public class PVo {
    private People people;
    private Person person;
  //get/set方法略 }

2)新建接口方法

int addPvo(PVo pVo);

3)插入语句

<insert id="Pvo" parameterType="PVo">
   insert into  user values(12,#{person.username},#{people.password})
</insert>

4)测试方法

@Test
    public void addPvo() {
        SqlSession session = build.openSession();
        UserDao userMapper = session.getMapper(UserDao.class);
        PVo pVo = new PVo();
        People people = new People();
        Person person = new Person();
        people.setPassword("admin");
        person.setUsername("zhangSan");
        pVo.setPeople(people);
        pVo.setPerson(person);
        userMapper.addPvo(pVo);
        session.commit();//提交事务
    }

5.2 resultMap的使用

当查询的结果不仅仅是一个对象的全部属性时,如果再创建一个对象来封装数据就显得格外的麻烦,那么可以使用resultMap来对属性进行重定义,这样就可以直接返回一个map的结果。具体的用法见代码中的注释。

5.2.1复杂查询一

查询用户的id,用户名以及所对应的成绩的id和具体成绩(一对一)

1)数据库执行sql

create table score (
    id int primary key,
    grade float,
    u_id int
);
insert into score values(1,99,1);
insert into score values(2,90,2);
insert into score values(3,85,3);

2)新建成绩类

package com.zxh.entity;

public class Score {

    private int id;
    private double grade;
    private int u_id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public double getGrade() {
        return grade;
    }

    public void setGrade(double grade) {
        this.grade = grade;
    }

    public int getU_id() {
        return u_id;
    }

    public void setU_id(int u_id) {
        this.u_id = u_id;
    }

    @Override
    public String toString() {
        return "Score{" +
                "id=" + id +
                ", grade=" + grade +
                ", u_id=" + u_id +
                '}';
    }
}

3)给User类添加属性添加set和get及tostring方法

....
private Score score;
....

4)新建接口方法

List<User> findUserAndScore();

5)查询语句

 <!-- 复杂查询:查询用户的id,用户名以及所对应的成绩的id和具体成绩 -->
    <!--定义表数据与组合类的映射关系,id是唯一标识,type是类型-->
    <resultMap id="userAndScore" type="User">
        <!--id是主键映射,result是非主键映射,column是数据库中的列名,properties是对象的属性名-->
        <!--如果多个表中的属性名一样,要注意区分,如这里的id-->
        <id column="uid" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <!--association对属性是对象的变量的深入映射,适用于一对一的关系-->
        <association property="score" javaType="Score">
            <id column="sid" property="id"></id>
            <result column="grade" property="grade"></result>
            <result column="u_id" property="u_id"></result>
        </association>
    </resultMap>
    <!--这里的返回类型必须是map集合-->
    <select id="findUserAndScore" resultMap="userAndScore">
        select user.id uid, username,score.id sid,grade from user,score where user.id=score.u_id
    </select>

6)测试方法

@Test
public void findUserAndScore(){
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
List<User> list=userMapper.findUserAndScore();
System.out.println(list);
}

分析:在这对一对一的关系中,mybatis使用association来标识另一个对象属性,同时要指定返回的类型是map集合。

5.2.2复杂查询二

查询用户的id,用户名以及所对应的成绩的id和具体成绩(一对多)

1)在插入一条数据。此查询是基于上述查询一的,请按步骤进行。

insert into score values(4,75,2);

2)给User类添加属性并添加set和get及tostring方法

private List<Score> scores;

3)查询语句。需要把查询一的查询语句注释!

<resultMap id="userAndScore" type="User">
    <id column="uid" property="id"></id>
    <result column="username" property="username"></result>
    <result column="password" property="password"></result>
    <!--collection对属性是对象的变量的深入映射,适用于一对多的关系-->
    <!--javaType指属性是什么类型,ofType指集合中装的什么类型-->
    <collection property="scores" javaType="java.util.List" ofType="Score">
        <id column="sid" property="id"></id>
        <result column="grade" property="grade"></result>
        <result column="u_id" property="u_id"></result>
    </collection>
</resultMap>
<!--这里的返回类型必须是map集合-->
<select id="findUserAndScore" resultMap="userAndScore">
    select user.id uid, username,score.id sid,grade from user,score where user.id=score.u_id
</select>

分析:在这对一对多的关系中,mybatis使用collection来标识另一个集合对象属性,同时要指定返回的类型是map集合。

6.动态sql

6.1 if标签

1)语法

当标签里面test的内容为true时才会去执行if里面的语句。

2)示例

查询:根据id或用户名查询

<select id="findByMap"  resultType="User">
select * from user where 1=1
<if test="id!=null">
and id=#{id}
</if>
<if test="username!=null and username!=''">
and username like '%${username}%'
</if>
</select>

此查询语句中,分别以int类型的id和string类型的username进行判断查询。而id并没有判断是否是空串,原因是它不是字符串,同理date类型等其他类型都不能加是否是空串的条件判断,否则会报错。

6.2 where标签

1)语法

where会自动去识别,当sql语句中已经有where那么它会直接拼接where里面的内容,如果没有就直接使用;另外where里面的and也类似,如果已经有where就使用and,如果没有就舍弃第一个and。

2)示例

查询:根据id或用户名查询,如果都为空就查询所有

<select id="findById2" resultType="User">
select * from user
<where>
<if test="value!=null">
and id=#{value}
</if>
</where>
</select>

这个示例其实是对上面示例的对比,两种方式,查询的结果是一样的。

6.3 foreach标签

1)语法

用来遍历集合等,用于传入参数是多个相同类型的查询,可以使用在in,limit,between。。。

2)示例

查询:传入多个id的list集合查询用户信息

<select id="findByIn" parameterType="java.util.List" resultType="User">
    select * from user
    <!--如果传入参数是list类型,必须使用list获取,并且使用and-->
    <if test="list.size()>0 and list!=null">
        where id in
        <!--collection要遍历的集合,open开始的符号,close结束的符号,separator分隔符-->
        <!--index是索引,item是每一条内容,这里是list.get(i)-->
        <foreach collection="list" open="(" separator="," close=")" index="i" item="item" >
            #{item}
        </foreach>
    </if>
</select>

测试方法

 @Test
    public void test4() {
        SqlSession session = build.openSession();
        UserDao userMapper = session.getMapper(UserDao.class);
        List<Integer> list=new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(22);
        List<User> list2 = userMapper.findByIn(list);
        System.out.println(list2);
    }

6.4sql片段

将会重复使用的sql语句抽取出来,需要使用的地方直接引入

<!--sql片段-->
<sql id="select">
    select * from user
</sql>

<select id="findById2"  resultType="User">
    <!--引入sql片段-->
    <include refid="select"/>
    where id=#{value}
</select>

7.延迟加载

需要查询关联信息时,我们先查询一部分信息,再关联查询关联信息,叫延迟加载。主要通过resultMap实现延迟加载。延迟加载需要导入cglib以及asm的jar包。

7.1打开延时加载的开关

在SqlMapConfig.xml中配置:

<settings>
    <!-- 延迟加载开关 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 当设置为true的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载-->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

7.2写sql语句

根据用户名和密码查询出id,然后再根据id查询对应的成绩

查询之后可以看到先执行一次查询,然后再去执行后面的查询,并没有一次性查询出结果。

8. Mybatis缓存

将从数据库查询的数据存储到内存中缓存起来,这样就不用从数据库中查询数据而从缓存中查询,提高查询的速度,减少对数据库的访问。

8.1一级缓存

1)原理

当执行两条相同的查询语句时,mybatis只执行一次查询,map中存储了sql执行查询的结果集。是session级别的缓存,当执行增删改中的任何一个操作,缓存就会清空。

 

第一次查询先去缓存中找是否有缓存数据,发现没有,查询数据库,将查询到的数据写入sqlsession的一级缓存区域。

第二次查询先去缓存中找是否有缓存数据,发现有,直接从缓存区域中取出数据返回。如果执行sqlsession的添加、修改、删除等操作,会执行commit,最终会清空缓存。

2)一级缓存查询:

@Test
public void test6(){
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = userMapper.findById(2);
System.out.println(user);
System.out.println("----------");
User user2=userMapper.findById(2);
System.out.println(user2);
}

从查询结果中可以看出只进行了一次的查询,第二次的查询直接从缓存中获取的。

3)一级缓存查询中执行增加操作:

@Test
public void test7(){
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = userMapper.findById(2);
System.out.println(user);
User user3=new User();
user3.setUsername("方启豪6号");
user3.setPassword("12315");
userMapper.addUser(user3);
session.commit();//提交事务
System.out.println("----------");
User user2=userMapper.findById(2);
System.out.println(user2);
}

只要清空了session,那么就清除了缓存,就需要重新查询。也可以手动清空session,语句是

8.2二级缓存

1)原理

二级缓存是mapper(命名空间)级别的缓存,默认是开启的,只有session提交或关闭时才能把结果提交到二级缓存中,当执行增删改中的任何一个操作,缓存就会清空。

不同的sqlsession都要调用mapper下的sql语句发起数据库请求。sqlsession1执行UserMapper下的查询用户请求先从二级缓存中查找有没有数据,如果没有就从数据库中查询,并且将查询到数据存储二级缓存中。

sqlsession2执行UserMapper下的同一个查询用户请求,先从二级缓存中查找有没有数据,如果有就从二级缓存中查询数据,返回。

如果有一个sqlsession3执行UserMapper下添加、修改、删除语句,执行commit操作后,将UserMapper下的所有缓存数据全部清空。

2)二级缓存的使用

二级缓存的使用需要进行配置:

第一步:在SqlMapConfig.xml的settings中加一行代码:

<!--开启并标识二级缓存-->
<setting name="cacheEnabled" value="true"/>

第二步:在userDao.xml中加一行代码:

第三步:User类要实现Serializable接口

由于不经常使用,在此代码省略。

9. Mybatis注解

9.1@Param参数传入

当参数少于4个的时候可以使用注解参数的传入,如果参数过多,就使用原始pojo的方式

UserDao类:  

//使用注解Param传递参数,引号里面的参数是要使用的参数,如#{username}
User findByNmAndPwd2(@Param("username")String username,@Param("password")String password);

userDao.xml中sql:

<select id="findByNmAndPwd2" resultType="User">
    select * from user where username=#{username} and password=#{password}
</select>

测试类:

@Test
public void test8() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = userMapper.findByNmAndPwd2("方启豪","123");
System.out.println(user);
}

9.2@Insert @Update @Delete

此注解不需要userDao.xml文件,这三个用法雷同,以update为例:

UserDao类:

//这里参数传的是一个对象
@Update("update user set username=#{user.username}, password=#{user.password} where id=#{user.id}")
void updateUser2(@Param("user")User user);

测试类:

@Test
public void test9() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user3 = new User();
user3.setId(10);
user3.setUsername("方启豪7号");
user3.setPassword("123155151");
userMapper.updateUser2(user3);
session.commit();
}

9.3@Select

此注解不需要userDao.xml文件

UserDao类:

@Select("select * from user where id=#{id}")
User findById2(@Param("id") Integer id);

测试类:

@Test
public void test10(){
    SqlSession session = build.openSession();
    UserDao mapper=session.getMapper(UserDao.class);
    User user=mapper.findById(14);
    System.out.println(user);
}

10.异常问题

10.1 Mybatis异常 There is no getter for property...

在dao层修改:

List<Article> recommandList(@Param("siteid") Integer siteid);

如上修改,给siteid @Param注入getter 即可。

总结:如果xml的parameterType属性时Map,则不需要加@Param。如果是一个int,string这种类型的参数,需要在Dao层加@Param注解;只有一个参数,xml不用if,可不加。有多个参数,dao层每个参数都要加上@Param。如果传入的参数特别多,建议直接传入一个Map。

 

就是这么简单,你学废了吗?感觉有用的话,给笔者点个赞吧 !
原文地址:https://www.cnblogs.com/zys2019/p/11426220.html