• 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。

     

    就是这么简单,你学废了吗?感觉有用的话,给笔者点个赞吧 !
  • 相关阅读:
    ps:点阵格式图像
    ps:图像尺寸
    ps:HSB色彩模式
    git上传文件夹的问题
    sublime下载emmet
    git Octotree:提供项目目录,方便用户在线快速浏览项目结构【转载】
    git@github.com出现Permission denied (publickey)
    less:避免编译
    less:@arguments变量
    less嵌套规则
  • 原文地址:https://www.cnblogs.com/zys2019/p/11426220.html
Copyright © 2020-2023  润新知