数据库学习记录 Day5(Mybatis进阶)

Day 5

2019年7月24日。
这是我学习数据库的第五天。
这一天,我学到了以下的知识。

分页

Mysql的分页语句

select * from user limit #{startIndex},#{pageSize};
# startIndex : 起始位置 ,默认是0开始
# pageSize :页面大小
# 如何计算出当前页面
currentPage = (currentPage-1* pageSize  

使用Limit实现分页

  1. 编写dao接口,代码如下:

    //查询全部用户实现分页
    List<User> selectUserByLimit(Map<String,Integer> map);
    
  2. 编写对应mapper文件的方法【参数可以使用map进行封装,方便参数传递】,代码如下:

    <select id="selectUserByLimit" parameterType="Map" resultType="User">
    select * from mybatis.user limit #{startIndex},#{pageSize}
    </select>
    
  3. 测试【模拟分页数据:currentPage,pageSize】,代码如下:

    @Test
    public void selectUserByLimit(){
    
    //创建sqlSession
    SqlSessionFactory sqlSessionFactory = MyBatisUtils.getSqlSessionFactory();
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    //准备数据
    int currentPage = 2;//当前是第几页
    int pageSize = 2; //页面大小
    
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("startIndex",(currentPage-1)*pageSize);
    map.put("pageSize",pageSize);
    
    //测试
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    List<User> users = mapper.selectUserByLimit(map);
    
    for (User user : users) {
        System.out.println(user);
    }
    
    sqlSession.close();//关闭连接
    
    }
    

使用RowBounds实现分页

  1. 编写dao接口,代码如下:

    //查询全部用户实现分页使用RowBounds
    List<User> selectUserByRowBounds();
    
  2. 编写对应mapper文件的方法,代码如下:

    <select id="selectUserByRowBounds" resultType="User">
    select * from mybatis.user
    </select>
    
  3. 测试【模拟分页数据:currentPage,pageSize】,代码如下:

    @Test
    public void selectUserByRowBounds(){
    //创建sqlSession
    SqlSessionFactory sqlSessionFactory = MyBatisUtils.getSqlSessionFactory();
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    int currentPage = 2; //当前页
    int pageSize = 2; //页面大小
    
    RowBounds rowBounds = new RowBounds((currentPage - 1) * pageSize, pageSize);
    
    //注意点;使用RowBounds就不能使用getMapper了
    //selectList: 接收一个List
    //selectMap: 接收一个Map
    //selectOne : 接收只有一个对象的时候
    
    List<User> users = sqlSession.selectList("dao.UserDao.selectUserByRowBounds", null, rowBounds);
    
    for (User user : users) {
        System.out.println(user);
    }
    }
    

Limit和RowBounds的区别

  • rowBounds本质就是封装了limit
  • limit是在SQL层面实现分页
  • rowBounds是在代码层面实现分页

使用注解开发

面向接口编程

提出的原因:解耦,方便拓展,提高代码的复用性,上层不用管下层实现,只用去调用对应的接口即可,规范性好

  • 面向过程编程:随着系统越来越大,无法使用面向过程的思想满足,只能使用面向对象编程
  • 面向对象编程:所有的系统耦合性高,所有的功能都是由许许多多不同的对象去完成的
  • 面向接口编程:约束开发人员操作,而且方便扩展以及规划,实现更深层次的分离(定义与实现的一个分离

接口 & 抽象类
接口可以反映一个开发人员的水平高低,以及对系统架构的理解

简介

早期的mybatis都是使用xml进行配置,直到注解的出现,注解可以替代一些xml中的配置
不需要xml配置!

CRUD的注解

  • @insert():增
  • @delete():删
  • @update():改
  • @select():查

优化项目

事务优化
mybatis开发人员也想到了。有一个构造器,可以实现事务自动提交,代码如下:

openSession(true); // openSession构造器如果参数为true,就会自动提交事务,不用再使用commit()方法区提交

别名优化
为pojo包下的实体类(User)自动设置别名,代码如下:

<!--配置别名-->
<typeAliases>
    <!--<typeAlias type="pojo.User" alias="User"/>-->
    <package name="pojo"/>
</typeAliases>

工具类优化
自动提交事务,代码如下:

//获得一个带事务自动提交功能的SqlSession公共的方法
public static SqlSession getSqlSession(){
    //自动提交事务
    return sqlSessionFactory.openSession(true);
}

使用注解进行开发

  • 在dao包下编写接口UserDao,代码如下:

    import org.apache.ibatis.annotations.*;
    
    import java.util.List;
    
    public interface UserDao {
    
    //查询全部用户
    @Select("select * from user")
    List<User> getUserList();
    
    //通过ID查询用户
    @Select("select * from user where id = #{id}")
    User getUserById(@Param("id") int id);
    
    //添加用户
    @Insert("insert into user(id,name,pwd) values (#{id},#{name},#{pwd})")
    int addUser(User user);
    
    //修改用户信息
    @Update("update user set name = #{name}, pwd = #{pwd} where id = #{id}")
    int updateUser(User user);
    
    //删除用户
    @Delete("delete from user where id =#{uid}")
    int deleteUser(@Param("uid") int id);
    
    }
    
  • 在resources编写mybatis的配置文件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>
    
    <!--配置文件修改-->
    <properties resource="database.properties"/>
    
    <!--Mybatis设置-->
    <settings>
        <!--默认日志实现-->
        <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
    
        <!--Log4j实现-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    
    <!--配置别名-->
    <typeAliases>
        <!--<typeAlias type="com.kuang.pojo.User" alias="User"/>-->
        <package name="pojo"/>
    </typeAliases>
    
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    
    <mappers>
        <!--class对应的是一个接口类-->
        <!--resource对应的是一个接口类的映射文件-->
        <mapper class="dao.UserDao"/>
    </mappers>
    
    </configuration>
    
  • 在Test文件夹下编写测试类,代码如下:

    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    import sun.rmi.server.UnicastServerRef;
    
    import java.util.List;
    
    
    public class UserDaoTest {
    
    @Test
    public void getUserList(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();//带自动提交事务
    
        UserDao mapper = sqlSession.getMapper(UserDao.class);
    
        List<User> userList = mapper.getUserList();
    
        for (User user : userList) {
            System.out.println(user);
        }
    
        sqlSession.close();//关闭sqlSession;
    
    }
    
    @Test
    public void getUserById(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();//带自动提交事务
    
        UserDao mapper = sqlSession.getMapper(UserDao.class);
    
        User user = mapper.getUserById(1);
    
        System.out.println(user);
    
        sqlSession.close();//关闭sqlSession;
    
    }
    
    
    @Test
    public void addUser(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();//带自动提交事务
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        User user = new User(5, "阿猫", "like-dog");
        int i = mapper.addUser(user);
        System.out.println(i);
    
        sqlSession.close();//关闭sqlSession;
    
    }
    
    @Test
    public void updateUser(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();//带自动提交事务
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        User user = new User(5, "阿狗", "like-cat");
        int i = mapper.updateUser(user);
        System.out.println(i);
    
        sqlSession.close();//关闭sqlSession;
    
    }
    
    @Test
    public void deleteUser(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();//带自动提交事务
        UserDao mapper = sqlSession.getMapper(UserDao.class);
    
        int i = mapper.deleteUser(5);
        System.out.println(i);
    
        sqlSession.close();//关闭sqlSession;
    
    }
    }
    

【注意事项】

  • 需要开启事务自动提交
  • @param参数尽量都写上,如果有多个参数,就必须填写

映射

首先掌握两个单词:

  • association:联系,关联,多个人可以关联到一个人
  • collection:集合,一个人有一个集合,包含多个人

多对一处理

多个对象对应一个对象
比如:你们都是我的学生,多个学生对应一个老师
处理方案

  • 处理方式一
    使用数据库的思想处理:连表查询
  1. 定义dao接口,代码如下:

    List<Student> getStudents();
    
  2. 编写查询语句,步骤如下:

    1. 查询学生信息 id name tid , 由于我们要得到老师的信息,我们需要联表查询
    2. 查询老师的信息 id name
    <!--遇到问题:学生类中关联老师: 多个学生对应一个老师 -->
    <!--<select id="getStudents" resultType="Student">-->
    <!--select s.id,s.name,t.name from mybatis.student as s,mybatis.teacher as t-->
    <!--where s.tid = t.id-->
    <!--</select>-->
    
    
    <!--解决问题方式一:按查询结果嵌套处理,模拟数据库思想;
    -->
    <select id="getStudents" resultMap="StudentTeacher">
    select * from mybatis.student
    </select>
    
    <resultMap id="StudentTeacher" type="Student">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <!--属性和字段对应  , 类和表对应  , 对象和记录
    关联一个字段
    需求:拿到老师这个类的属性
    
    association : 关联,多对一
        column : 数据库对应的列名
        property : 对应属性名
        javaType : 多对一字段对应的Java类型
        select : 关联一个语句
    -->
    <association column="tid" property="teacher" javaType="Teacher" select="getTeacher"/>
    </resultMap>
    
    <select id="getTeacher" resultType="Teacher">
    select * from mybatis.teacher where id = #{id}
    </select>
    
  3. 编写测试类,代码如下:

    @Test
    public void getStudents(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
        StudentDao mapper = sqlSession.getMapper(StudentDao.class);
    
        List<Student> students = mapper.getStudents();
    
        for (Student student : students) {
            System.out.println("学生姓名:"+student.getName()+"\t老师姓名:"+student.getTeacher().getName());
        }
    
    }
    
  • 处理方式二
    使用面向对象的思想处理:关联对象
  1. 定义dao接口,代码如下:

    List<Student> getStudentsTwo();
    
  2. 编写处理的mapper,步骤如下:

    1. 查询学生id,学生姓名,老师姓名,需要从学生表和老师表中查询
    2. 学生对应的类进行映射,发现老师一个对象 , 所以关联一个对象;
    <!-- 解决方式二:一个resultMap解决 , 模拟面向对象的思想-->
    <select id="getStudentsTwo" resultMap="StudentTeacher2">
    select s.id,s.name,t.name as tname from mybatis.student as s, mybatis.teacher as t
    where s.tid = t.id
    </select>
    
    <!--设置结果集映射ResultMap -->
    	<resultMap id="StudentTeacher2" type="Student">
    	<id property="id" column="id"/>
     <result property="name" column="name"/>
    
    <!--直接关联一个老师-->
    <association property="teacher" javaType="Teacher">
        <result property="name" column="tname"/>
    </association>
    </resultMap>
    
  3. 编写测试类,代码如下:

    @Test
    public void getStudentsTwo(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
    StudentDao mapper = sqlSession.getMapper(StudentDao.class);
    
    List<Student> students = mapper.getStudentsTwo();
    
    for (Student student : students) {
        System.out.println("学生姓名:"+student.getName()+"\t老师姓名:"+student.getTeacher().getName());
    }
    
    }
    

一对多处理

一个老师对应多个学生
一对多的业务:使用connection集合
环境搭建
一个老师对应多个学生,所以要编写实体类,代码如下:

public class Teacher {
    private int id;
    private String name;

    //一个老师对应对个学生
    private List<Student> students;
}

代码编写

  1. 编写dao接口,代码如下:

    public interface TeacherDao {
    
    //获得一个老师下的所有学生信息; 老师是包含学生的集合;
    Teacher getTeacher(int id);
    
    Teacher getTeacherTwo(int id);
    
    }
    
  2. 编写对应的mapper文件,代码如下:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="dao.TeacherDao">
    
    <!--一对多的处理-->
    <!--面向对象方式解决-->
    <select id="getTeacher" resultMap="TeacherStudent">
        select s.name sname,s.id sid,t.id tid, t.name tname
        from mybatis.student as s,mybatis.teacher as t
        where s.tid = t.id and t.id = #{id}
    </select>
    <resultMap id="TeacherStudent" type="Teacher">
        <result property="name" column="tname"/>
        <collection property="students" ofType="Student">
            <id property="id" column="sid"/>
            <result property="name" column="sname"/>
        </collection>
    </resultMap>
    
    
    <!--数据库思想-->
    <select id="getTeacherTwo" resultMap="TeacherStudent2">
        select * from mybatis.teacher where id = #{id}
    </select>
    <resultMap id="TeacherStudent2" type="Teacher">
        <collection property="students" javaType="ArrayList" ofType="Student" column="id" select="T2"/>
    </resultMap>
    <select id="T2" resultType="Student">
        select * from mybatis.student where tid = #{id}
    </select>
    
    </mapper>
    
  3. 编写测试类,代码如下:

    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    
    public class TeacherDaoTest {
    @Test
    public void getTeacher(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        TeacherDao mapper = sqlSession.getMapper(TeacherDao.class);
        Teacher teacher = mapper.getTeacher(1);
    
        System.out.println(teacher.getName());
        System.out.println(teacher.getStudents());
    
    }
    
    @Test
    public void getTeacherTwo(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        TeacherDao mapper = sqlSession.getMapper(TeacherDao.class);
        Teacher teacher = mapper.getTeacherTwo(1);
    
        System.out.println(teacher.getName());
        System.out.println(teacher.getStudents());
    
    }
    }
    

总结

多对一:association,关联

一对多:collection,集合

两种解决方式:

  • 面对对象的思想:关联对象
  • SQL语句思想:联表查询

动态SQL & 缓存

MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。

动态SQL就是指根据不同查询条件,生成不同的SQL语句

在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。

if

参数test:里面的表达式如果为ture则执行,否则不执行,代码如下:

if(title != null)
<if test="title != null">
AND title like #{title}
</if>

choose

有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句,代码如下:

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
    
    
    switch (exp){
    	case 1:
    		break;
    	case 2:
    		break;
    }
    
</select>

trim[where,set]

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>
<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>
<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>
<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

foreach

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>

代码测试

测试模糊查询

  1. 接口编写,代码如下:
//模糊查询,可以通过自定义条件查询
List<User> getUserByLike(Map<String,Object> map);
  1. 映射文件编写,代码如下:
<select id="getUser" resultType="User">
    select * from mybatis.user
</select>

<select id="getUserByLike" resultType="User" parameterType="Map">
    select * from mybatis.user
    <where>
        <if test="name!=null">
            name like CONCAT('%',#{name},'%')
        </if>
        <if test="id!=null">
            and id = #{id}
        </if>
    </where>
</select>
  1. 测试类编写,代码如下:
@Test
public void getUserByLike(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);

    Map<String,Object> map = new HashMap<String,Object>();

    map.put("name","秦");
    map.put("id",1);

    List<User> users = mapper.getUserByLike(map);
    for (User user : users) {
        System.out.println(user);
    }
}

注意点:太过复杂的逻辑不建议使用动态SQL,简单的话可以直接使用动态SQL实现;

缓存

如果开启缓存,相关的SQL语句就会存储在缓存中,减少数据库交互操作的时间

在mapper映射文件中,添加一个标签,代码如下:

<!--开启缓存-->
<cache/>

如果要CRUD操作要查询结果需要缓存,可以使用usrCache;代码如下:

<!--
useCache: 是否开启缓存
使用缓存可以解决问题:
    查询出来的结果暂时保存着,消耗内存资源;
    如果短时间查询同样的语句比较多,可以提高速度;
-->
<select id="getUser" resultType="User" useCache="true">
    select * from mybatis.user
</select>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赈川

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值