首页 > 其他分享 >Mybatis学习记录

Mybatis学习记录

时间:2023-02-15 18:56:40浏览次数:47  
标签:mapper 映射 记录 查询 学习 sqlSession emp Mybatis id

尚硅谷:https://www.bilibili.com/video/BV1Ya411S7aT?share_source=copy_web

Mybatsi简介

Mybatis历史

前身iBatis。iBatis是一个基于Java的持久层框架。iBatis提供的持久层框架包括SQL Maps和DataAccessObjects(DAO)。

SQLMaps:SQL映射,即将Java的实体类对象映射为数据库中的一条数据,或数据库的一条记录查询为Java中的实体类对象

Mybatis特性

  1. 支持定制化SQL、存储过程以及高级映射的优秀的持久层框架

  2. 避免了几乎所有的JDBC代码和手动设置参数以及获取结果集

  3. 可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录

  4. 是一个半自动的ORM(Object Relation Mapping)框架

Mybatis的配置

导入依赖

 <dependencies>
     <dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis</artifactId>
         <version>3.5.2</version>
     </dependency>
     <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>8.0.13</version>
     </dependency>
     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>3.8.2</version>
     </dependency>
 </dependencies>

创建核心配置文件(连接数据库)

 <?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>
     <!--引入配置文件,此后就可以在当前文件中使用${key}的方式访问value-->
     <properties resource="jdbc.properties"/>
     <!--
     设置别名
     alias:别名。可以不写
     不区分大小写
     -->
     <typeAliases>
  <!--<typeAlias type="com.zwb.pojo.User"/>-->
         <!--将包下所有的类起别名-->
         <package name="com.zwb.pojo"/>
     </typeAliases>
     <!--
         environments:配置连接数据库的环境
         属性:
          default:设置默认使用环境
          id:设置环境的唯一标识,不能重复
     -->
     <!--配置连接数据库的环境-->
     <environments default="propertiesTest">
         <environment id="development">
            <!--
             transactionManager:设置事务管理器
             属性:
             type:设置事务管理方式
             type="JDBC|MANAGED"
             JDBC:表示使用JDBC中原生的事务管理方式
             MANAGED:被管理,例如Spring
             -->
             <transactionManager type="JDBC"/>
             <!--
             dataSource:设置数据源
             属性:
             type:设置数据源的类型
             type="POOLED|UNPOOLED|JNDI"
             POOLED:表示使用数据库连接池
             UNPOOLED:表示不使用数据库连接池
             JNDI:表示使用上下文中的数据源
             -->
             <dataSource type="POOLED">
                 <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                 <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8&amp;serverTimezone=UTC&amp;useSSL=false"/>
                 <property name="username" value="root"/>
                 <property name="password" value="123456"/>
             </dataSource>
         </environment>
         <environment id="propertiesTest">
             <transactionManager type="JDBC"/>
             <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>
     <!--引入mybatis的映射文件-->
     <mappers>
         <!--<mapper resource="com/zwb/mapper/UserMapper.xml"/>-->
         <package name="com.zwb.mapper"/>
     </mappers>
 </configuration>
 jdbc.driver=com.mysql.cj.jdbc.Driver
 jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
 jdbc.username=root
 jdbc.password=123456

<!--引入配置文件,此后就可以在当前文件中使用${key}的方式访问value--> <properties resource="jdbc.properties"/>

<!--设置别名 不区分大小写--> <typeAliases> <!--<typeAlias type="com.zwb.pojo.User"/>--> <!--将包下所有的类起别名--> <package name="com.zwb.pojo"/> </typeAliases>

<!-- 以包的方式引入映射文件 1.mapper接口和映射文件所在的包必须一致 2.mapper接口的名字和映射文件的名字必须一致 --> <package name="com.zwb.mapper"/>

创建mapper接口

mapper接口相当于以前的dao。区别在于,mapper仅仅是接口,不需要提供实现类

 public interface UserMapper {
     int insertUser();
 }

创建映射文件

ORM:对象关系映射

  • 对象:Java的实体类对象

  • 关系:关系型数据库

  • 映射:二则之间的关系

Java概念数据库概念
属性 字段/列
对象 记录/行
 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE mapper
         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
 ​
 <!--namespace=绑定一个对应的Mapper接口-->
 <mapper namespace="com.zwb.mapper.UserMapper">
     <!--
         mapper接口和映射文件要保证两个一致
         1.mapper接口和映射文件的namespace一致
         2.mapper接口的方法名要和映射文件sql的id保持一致
     -->
     <!--id为接口里的方法名,resultType为sql语句的返回值-->
     <!--int insertUser();-->
     <insert id="insertUser">
        insert into t_user values(null,'admin','123456',23,'男','[email protected]')
     </insert>
 </mapper>

测试

 @Test
     public void testInsert() throws IOException {
         // 获取核心配置文件的输入流
         InputStream is =Resources.getResourceAsStream("mybatis-config.xml");
         //获取SqlSessionFactoryBuilder对象
         SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
         //获取SqlSeesionFactory对象
         SqlSessionFactory sqlSessionFactory=sqlSessionFactoryBuilder.build(is);
         //获取sql的会话对象SqlSession,是Mybatis提供的操作数据库的对象
         //SqlSession sqlSession=sqlSessionFactory.openSession();//不会自动提交事务
         SqlSession sqlSession=sqlSessionFactory.openSession(true);//自动提交事务
         //获取UserMapper的代理实现类对象
         UserMapper mapper=sqlSession.getMapper(UserMapper.class);
         int result=mapper.insertUser();
         //提交事务
         //sqlSession.commit();
         System.out.println(result);
         sqlSession.close();
    }
  • SqlSession:代表Java程序和数据库之间的会话。(HttpSeesion是Java程序和浏览器之间的会话)

  • SqlSessionFactory:是“生产”SqlSession的“工厂”

  • 工厂模式:如果创建一个对象,使用的过程基本固定,那就可以把创建这个对象的相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”需要的对象

封装SqlSession创建流程

 public class SqlSessionUtil {
     public static SqlSession getSqlSession() {
         SqlSession sqlSession=null;
         try{
             //获取核心配置文件的输入流
             InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
             //获取SqlSessionFactroyBuilder对象
             SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
             SqlSessionFactory sessionFactory=sqlSessionFactoryBuilder.build(is);
             sqlSession=sessionFactory.openSession(true);
        }catch (IOException e){
             e.printStackTrace();
        }
         return sqlSession;
    }
 }

CRUD

 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE mapper
         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
 ​
 <!--namespace=绑定一个对应的Mapper接口-->
 <mapper namespace="com.zwb.mapper.UserMapper">
     <!--
         mapper接口和映射文件要保证两个一致
         1.mapper接口和映射文件的namespace一致
         2.mapper接口的方法名要和映射文件sql的id保持一致
     -->
     <!--id为接口里的方法名,resultType为sql语句的返回值-->
     <!--int insertUser();-->
     <insert id="insertUser">
         insert into t_user values(null,'admin','123456',23,'男','[email protected]')
    </insert>
     <!--updateUser()-->
     <update id="updateUser">
         update t_user set username='root',password='123' where id=3
    </update>
     <!--   deleteUser-->
     <delete id="deleteUser">
         delete from t_user where id=3
    </delete>
     <!--
     resultType:设置结果类型,即查询的数据要转换的java类型
     resultMap:自定义映射,处理一对多或多对一的映射关系
     -->
     <!--getUserById-->
     <select id="getUserById" resultType="com.zwb.pojo.User">
         select * from t_user where id=1
    </select>
     <!--getAllUser()-->
     <select id="getAllUser" resultType="com.zwb.pojo.User">
         select * from t_user
    </select>
 </mapper>
 public interface UserMapper {
     int insertUser();
     int updateUser();
     int deleteUser();
     User getUserById();
     List<User> getAllUser();
 }
 ​
     @Test
     public void testInsert() throws IOException {
         // 获取核心配置文件的输入流
         InputStream is =Resources.getResourceAsStream("mybatis-config.xml");
         //获取SqlSessionFactoryBuilder对象
         SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
         //获取SqlSeesionFactory对象
         SqlSessionFactory sqlSessionFactory=sqlSessionFactoryBuilder.build(is);
         //获取sql的会话对象SqlSession,是Mybatis提供的操作数据库的对象
         //SqlSession sqlSession=sqlSessionFactory.openSession();//不会自动提交事务
         SqlSession sqlSession=sqlSessionFactory.openSession(true);//自动提交事务
         //获取UserMapper的代理实现类对象
         UserMapper mapper=sqlSession.getMapper(UserMapper.class);
         int result=mapper.insertUser();
         //提交事务
         //sqlSession.commit();
         System.out.println("结果:"+result);
         sqlSession.close();
    }
     @Test
     public void UpdateTest(){
         SqlSession sqlSession= SqlSessionUtil.getSqlSession();
         UserMapper mapper=sqlSession.getMapper(UserMapper.class);
         mapper.updateUser();
         sqlSession.close();
    }
     @Test
     public void deleteUser(){
         SqlSession sqlSession=SqlSessionUtil.getSqlSession();
         UserMapper mapper=sqlSession.getMapper(UserMapper.class);
         mapper.deleteUser();
         sqlSession.close();
    }
     @Test
     public void getUserByIdTest(){
         SqlSession sqlSession=SqlSessionUtil.getSqlSession();
         UserMapper mapper=sqlSession.getMapper(UserMapper.class);
         System.out.println(mapper.getUserById());
         sqlSession.close();
    }
     @Test
     public void geAlltUserTest(){
         SqlSession sqlSession=SqlSessionUtil.getSqlSession();
         UserMapper mapper=sqlSession.getMapper(UserMapper.class);
         System.out.println(mapper.getAllUser());
         sqlSession.close();
    }

Mybatis获取参数值的两种方式

Mybatis或取参数的两种方式:${}和#{}

  • ${}的本质就是字符串的拼接

    • 使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需手动加单引号

  • #{}本质就是占位符的赋值

    • 占位符赋值的方式拼接sql,此时为字符串类型和日期类型的字段进行赋值时,可自动添加单引号

单个字面量类型的参数

若mapper接口中的方法参数为单个字面量类型,此时可以使用${}和#{}获取参数的值,注意${}需要手动加单引号

 <select id="getUserByUsername" resultType="user">
         <!--select * from t_user where username=#{name}-->
        select * from t_user where username='${username}'
     </select>

多个字面量类型的参数

若mapper接口的方法参数为多个时

此时Mybatis会自动将这些参数放在一个map集合中,以arg0,arg1...为键,以参数为值;以param1,...为键,以参数为值;因此只需通过${}和#{}访问集合的键就可以获取值

 <!--checkLogin(String username,String password)-->
     <select id="checkLogin" resultType="User">
         <!--select * from t_user where username=#{param1} and password=#{param2}-->
        select * from t_user where username='${param1}' and password='${param2}'
     </select>
 User checkLogin(String username,String password);

自定义map

 User checkLoginByMap(Map<String,Object> map);
 ​
 Map<String,Object> map=new HashMap<>();
 map.put("username","admin");
 map.put("password","123456");
 User user=mapper.checkLoginByMap(map);
 <!--User checkLoginByMap(Map<String,Object> map);-->
     <select id="checkLoginByMap" resultType="User">
         <!--select * from t_user where username=#{param1} and password=#{param2}-->
        select * from t_user where username='${username}' and password='${password}'
     </select>
 </mapper>

实体类

 void insertUser(User user);
 <insert id="insertUser">
        insert into t_user values(null,#{username},#{password},#{age},#{gender},#{email})
     </insert>

注解@Param()

 User checkLoginByParam(@Param("username") String username,@Param("password") String password);
 <select id="checkLoginByParam" resultType="User">
         <!--select * from t_user where username=#{username} and password=#{password}-->
        select * from t_user where username='${username}' and password='${password}'
     </select>

[password, param1, username, param2]

注解会将map集合中的arg0...替换为自定义的名称

Mybatis的各种查询

查询一个实体类对象

 /**
 * 根据id查询
 * @param id
 * @return
 */
 User getUserById(@Param("id") Integer id);
 <!--User getUserById(Integer id);-->
 <select id="getUserById" resultType="User">
  select * from t_user where id=#{id}
 </select>

查询一个list集合

 /**
 * 查询所有用户
 * @return
 */
 List<User> getAllUser();
 <!--List<User> getAllUser()-->
     <select id="getAllUser" resultType="User">
        select * from t_user
     </select>

查询单个数据

 /**
      * 查询用户数
      */
     Integer getCount();
 <select id="getCount" resultType="Integer">
        select COUNT(*) from t_user
     </select>

查询一条数据为map集合

 /**
      * 根据id查询用户信息为map集合
      * @param id
      * @return
      */
     Map<String,Object> getUserByIdToMap(@Param("id") Integer id);
 <!--getUserByIdToMap(@Param("id") Integer id)-->
     <select id="getUserByIdToMap" resultType="map">
        select * from t_user where id=#{id}
     </select>

查询多条数据为map集合

 /**
      * 查询所有的用户信息为一个Map集合
      * 若查询返回结果有多条时,又要将结果存入map集合时,有两种解决方案
      * 1.将mapper接口返回值设置为泛型是map的list集合
      * 2.通过注解@MapKey(),以某个字段为键,其余数据为值,组成map的键值对
      * @return
      */
     // List<Map<String,Object>> getAllUserToMap();
     @MapKey("id")//以id为键,其余数据为值,组成map的键值对
     Map<String,Object> getAllUserToMap();
 <!--getAllUserToMap()-->
     <select id="getAllUserToMap" resultType="map">
        select * from t_user
     </select>

查询的结果有实体类,用实体类对象接收

查询的结果无实体类,用map集合方式接收

Mybatis为Java的常用类型设置了别名 Integer:int,Integer int:int,integer Map:map String:string

特殊SQL的执行

模糊查询

 /**
      * 通过用户名模糊查询用户信息
      * @param fuzzy
      * @return
      */
     List<User> getUserByLike(@Param("fuzzy")String fuzzy);
 <select id="getUserByLike" resultType="User">
         <!--select * from t_user where username like '%${fuzzy}%'-->
         <!--select * from t_user where username like concat('%',#{fuzzy},'%')-->
        select * from t_user where username like "%"#{fuzzy}"%"
     </select>

'%#{}%'无法使用,因为#{}是占位符,会被识别为字符串

批量删除

 /**
      * 拼接多个id传入,实现批量删除
      * @param ids
      */
     void deleteMoreUser(@Param("ids") String ids);
 <!--deleteMoreUser(@Param("ids") String ids)-->
     <delete id="deleteMoreUser">
        delete from t_user where id in(${ids})
     </delete>

不能使用#{},因为会自动在字符串两侧添加''

动态设置表名

 /**
 * 动态设置表名,查询用户信息
 * @param tableName
 * @return
 */
 List<User> getUserList(@Param("tableName")String tableName);
 <!--getUserList(@Param("tableName")String tableName)-->
     <select id="getUserList" resultType="User">
        select * from ${tableName}
     </select>

不能使用#{},因为会自动在字符串两侧添加'',而表名不能有''

获取自增id

在实现添加功能后,可以立刻获取自增的id

 /**
 * 添加用户信息,并获取自增的主键
 * @param user
 */
 void insertUser(User user);
 <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
        insert into t_user value(null,#{username},#{password},#{age},#{gender},#{email})
 </insert>
 @Test
     public void testInsertUser(){
         SqlSession sqlSession= SqlSessionUtil.getSqlSession();
         SpecialSQLMapper specialSQLMapper=sqlSession.getMapper(SpecialSQLMapper.class);
         User user=new User(null,"小明","123",20,"男","[email protected]");
         specialSQLMapper.insertUser(user);
         System.out.println(user);//User{id=6, username='小明', password='123', age=20, email='[email protected]'}
    }

useGeneratedKeys:表示当前添加功能使用了自增的主键 keyProperty:将添加的数据的自增主键为实体类类型的参数的属性赋值

自定义映射resultMap

resultMap处理字段和属性映射的关系

若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射

全局配置

 <!--
         字段名和属性名不一致,如何处理映射关系
         1.为查询的字段设置别名,和属性名保持一致
         2.当字段符合MySQL要求使用_,而属性符合java的要求使用驼峰,
         此时可以在Mybatis核心配置文件中设置一个全局配置,可自动将下划线映射为驼峰
  <setting name="mapUnderscoreToCamelCase" value="true"/>    
 -->
     <!--Emp getEmpByEmpId(@Param("empId") Integer empId);-->
     <select id="getEmpByEmpId" resultType="Emp">
         <!--select emp_Id empId,emp_name empName,age,gender from t_emp where emp_id=#{empId}-->
        select * from t_emp where emp_id=#{empId}
     </select>
 Emp getEmpByEmpId(@Param("empId") Integer empId);

自定义映射

 <!--
         resultMap:设置自定义的映射关系
         id:唯一标识
         type:处理映射关系的实体类的类型
         常用的标签
         id:处理主键和实体类中实现的映射关系
         result:处理普通字段和实体类中的属性的映射关系
         column:设置映射关系中的字段名,必须是sql查询出的某个字段
         property:设置映射关系中属性的属性名,必须是处理的实体类类型中的属性名
  association:处理多对一的映射关系(处理实体类类型的属性)
  collection:处理一对多的映射关系(处理集合类型的属性)
     -->
     <resultMap id="empResultMap" type="Emp">
         <id column="emp_id" property="empId"/>
         <result column="emp_name" property="empName"/>
         <result column="age" property="age"/>
         <result column="gender" property="gender"/>
     </resultMap>
     <select id="getEmpByEmpId" resultMap="empResultMap">
        select * from t_emp where emp_id=#{empId}
     </select>

对一是对象:private Dept dept;

对多是集合

处理多对一的映射关系

 public class Emp {
     private Integer empId;
     private String empName;
     private Integer age;
     private String gender;
     private Dept dept;
 }    
  • 级联方式处理

     /**
     * 获取员工及对应部门的信息
     * @param empId
     * @return
     */
     Emp getEmpAndDeptByEmpId(@Param("empId")Integer empId);
     <resultMap id="empAndDeptResultMap" type="Emp">
             <id column="emp_id" property="empId"/>
             <result column="emp_name" property="empName"/>
             <result column="age" property="age"/>
             <result column="gender" property="gender"/>
             <result column="dept_id" property="dept.deptId"/>
             <result column="dept_name" property="dept.deptName"/>
         </resultMap>
         <!--getEmpAndDeptByEmpId-->
         <select id="getEmpAndDeptByEmpId" resultMap="empAndDeptResultMap">
            select t_emp.*,t_dept.*
            from t_emp left join t_dept
            on t_emp.dept_id=t_dept.dept_id
            where t_emp.emp_id=#{empId}
         </select>
  • association

     <resultMap id="empAndDeptResultMap" type="Emp">
             <id column="emp_id" property="empId"/>
             <result column="emp_name" property="empName"/>
             <result column="age" property="age"/>
             <result column="gender" property="gender"/>
             <!--
                 association:处理多对一的映射关系(处理实体类类型的属性)
                 property:设置需要处理映射关系的属性的属性名
                 javaType:设置要处理的属性的类型
             -->
             <association property="dept" javaType="Dept">
                 <id column="dept_id" property="deptId"/>
                 <result column="dept_name" property="deptName"/>
             </association>
         </resultMap>
  • 分步查询

     /**
          * 通过分步查询获取员工及对应部门的信息的第一步
          * @param empId
          * @return
          */
         Emp getEmpAndDeptByStepOne(@Param("empId")Integer empId);
     <resultMap id="empAndDeptByStepResultMap" type="Emp">
             <id column="emp_id" property="empId"/>
             <result column="emp_name" property="empName"/>
             <result column="age" property="age"/>
             <result column="gender" property="gender"/>
             <!--
                 property:设置需要处理映射关系的属性的属性名
                 select:设置分步查询的sql的唯一标识
                 column:将当前sql语句查询出的某个字段作为分步查询的sql的条件
      fetchType:在开启了延迟加载的环境中,通过该属性设置当前的分步查询是否使用延迟加载
                     eager(立即加载)|lazy(延迟加载)
             -->
             <association property="dept"
                          select="com.zwb.mapper.DeptMapper.getEmpAndDeptByStepTwo"
                          column="dept_id">
             </association>
         </resultMap>
         <!--getEmpAndDeptByStepOne-->
         <select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
            select * from t_emp where emp_id=#{empId}
         </select>
     /**
          * 通过分步查询获取员工及对应部门的信息的第二步
          * @return
          */
         Dept getEmpAndDeptByStepTwo(@Param("deptId")Integer deptId);
     <!--getEmpAndDeptByStepTwo-->
         <select id="getEmpAndDeptByStepTwo" resultType="Dept">
            select * from t_dept where dept_id=#{deptId}
         </select>

    分步查询的优点:可以实现延迟加载

    但需要在配置文件中开启全局配置

    <!--开启延迟加载--> <setting name="lazyLoadingEnabled" value="true"/> <!--按需加载--> <setting name="aggressiveLazyLoding" value="false"/>

    开启后,如果没有调用其他的表的字段,则不会执行其他sql语句

    如System.out.println(emp.getAge());则不会执行dept的sql语句

处理一对多的映射关系

 public class Dept {
     private Integer deptId;
     private String deptName;
     private List<Emp> emps;
 }
  • collection

     /**
     * 查询部门以及部门中对应的员工的信息
     * @param deptId
     * @return
     */
     Dept getDeptAndEmp(@Param("deptId")Integer deptId);
     <resultMap id="deptAndEmpResultMap" type="Dept">
             <id column="dept_id" property="deptId"/>
             <result column="dept_name" property="deptName"/>
             <!--
                 ofType:设置集合类型的属性中存储的数据的类型
             -->
             <collection property="emps" ofType="Emp">
                 <id column="emp_id" property="empId"/>
                 <result column="emp_name" property="empName"/>
                 <result column="age" property="age"/>
                 <result column="gender" property="gender"/>
             </collection>
         </resultMap>
         <!--getDeptAndEmp-->
         <select id="getDeptAndEmp" resultMap="deptAndEmpResultMap">
            select *
            from t_dept d LEFT JOIN t_emp e
            ON d.dept_id=e.dept_id
            WHERE d.dept_id=#{deptId}
         </select>
  • 分步查询

     /**
          * 通过分步查询来查询部门以及部门中的员工的第一步
          * @param deptId
          * @return
          */
         Dept getDeptAndEmpByStepOne(@Param("deptId")Integer deptId);
     <resultMap id="deptAndEmpResultMapByStep" type="Dept">
             <id column="dept_id" property="deptId"/>
             <result column="dept_name" property="deptName"/>
             <collection property="emps"
                         select="com.zwb.mapper.EmpMapper.getDeptAndEmpByStepTwo"
                         column="dept_id"></collection>
         </resultMap>
         <!--getDeptAndEmpByStepOne-->
         <select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpResultMapByStep">
            select * from t_dept where dept_id=#{deptId}
         </select>
     /**
          * 通过分步查询来查询部门以及部门中的员工的第二步
          * @param deptId
          * @return
          */
         List<Emp> getDeptAndEmpByStepTwo(@Param("deptId")Integer deptId);
     <!--getDeptAndEmpByStepTwo-->
         <select id="getDeptAndEmpByStepTwo" resultType="Emp">
            select * from t_emp where dept_id=#{deptId}
         </select>

 

小结

  • 关联-association (多对一)

  • 集合-collection(一对多)

  • javatType&ofType

    • javaType 用来指定实体类中属性的类型

    • ofType 用来指定映射到List或集合中的pojo类型,泛型中的约束类型

 

动态SQL

什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句

Where

where 元素只会在至少有一个子元素返回内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除,但内容后多余的AND无法去除。

If

通过test属性的表达式判断是否将标签中的内容拼接到sql语句中

 <!--getEmpByCondition-->
     <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
         <where>
             <if test="empName != null and empName != ''">
                emp_name=#{empName}
             </if>
             <if test="age != null and age != ''">
                and age=#{age}
             </if>
             <if test="gender != null and gender != ''">
                and gender=#{gender}
             </if>
         </where>
     </select>

trim

 <!--
         trim
         prefix、suffix:在标签中的内容前或后添加指定内容
         prefixOverrides、suffixOverrides:在标签中的内容前或后去除指定内容
     -->
     <select id="getEmpByConditionTwo" resultType="Emp">
        select * from t_emp
         <trim prefix="where" suffixOverrides="and">
             <if test="empName != null and empName != ''">
                emp_name=#{empName} and
             </if>
             <if test="age != null and age != ''">
                age=#{age} and
             </if>
             <if test="gender != null and gender != ''">
                gender=#{gender} and
             </if>
         </trim>
     </select>

choose

 <!--
         相当于if。。。else if。。。else
         when至少设置一个,otherwise最多设置一个
     -->
     <!--getEmpByChoose-->
     <select id="getEmpByConditionTwo" resultType="Emp">
        select * from t_emp
         <where>
             <choose>
                 <when test="empName != null and empName != ''">
                    emp_name=#{empName}
                 </when>
                 <when test="age != null and age != ''">
                    age=#{age}
                 </when>
                 <when test="gender != null and gender != ''">
                    gender=#{gender}
                 </when>
                 <otherwise>
 ​
                 </otherwise>
             </choose>
         </where>
     </select>

foreach

 /**
      * 批量添加员工信息
      * @param emps
      */
     void insertMoreEmp(@Param("emps") List<Emp> emps);
 <!--insertMoreEmp-->
     <insert id="insertMoreEmp">
        insert into t_emp values
         <foreach collection="emps" item="emp" separator=",">
            (null,#{emp.empName},#{emp.age},#{emp.gender},null)
         </foreach>
     </insert>
 /**
      * 批量删除
      * @param empIds
      */
     void deleteMoreEmp(@Param("empIds") Integer[] empIds);
 IN
 <!--deleteMoreEmp-->
     <delete id="deleteMoreEmp">
        delete from t_emp where emp_id in
         <foreach collection="empIds" item="empId" separator="," open="(" close=")">
                #{empId}
         </foreach>
     </delete>
 ​
 OR
 <delete id="deleteMoreEmp">
         <!--delete from t_emp where emp_id in-->
         <!--<foreach collection="empIds" item="empId" separator="," open="(" close=")">-->
         <!--       #{empId}-->
         <!--</foreach>-->
        delete from t_emp where
         <foreach collection="empIds" item="empId" separator="or">
            emp_id=#{empId}
         </foreach>
     </delete>

foreach collection:设置要循环的数组或集合 item:用一个字符串来表示数组或集合中的每一个数据 separator:设置每次循环的数据之间的分隔符 open:循环内容以什么开始 close:循环内容以什么结束

set

set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。set 元素会动态地在行首插入 set 关键字,并会删掉额外的逗号

 <update id="UpdateBlog" parameterType="map">
        update mybatis.blog
         <set>
             <if test="title!=null">
                title=#{title},
             </if>
             <if test="author!=null">
                author=#{author}
             </if>
         </set>
        where id=#{id}
     </update>

所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

SQL片段

有的时候,我们可能会将一些功能部分抽取出来,方便复用

  1. 使用sql标签抽取公共部分

     <sql id="if-title-author">
             <if test="title!=null">
                and title=#{title}
             </if>
             <if test="author!=null">
                and author=#{author}
             </if>
         </sql>
  2. 在需要使用的地方使用Include标签引用

     <select id="queryBlogIf" parameterType="map" resultType="blog">
            select * from mybatis.blog
             <where>
                          <include refid="if-title-author"></include>
             </where>
     ​
         </select>

    注意事项

    • 最好基于单表来定义SQL片段

    • 不要存在where标签

MyBatis的缓存

  • 什么是缓存

    • 存在内存中的临时数据

  • 为什么使用缓存

    • 减少和数据库的交互次数,减少系统开销,提高系统效率

  • 什么样的数据能使用缓存

    • 经常查询且不经常改变的数据

一级缓存

是SqlSession级别,通过一个SqlSession查询的数据会被缓存,下次查询相同数据时,就会从缓存中直接获取,不会从数据库重新访问

  • 使一级缓存失效的的情况

    • 不同的SqlSession对应不同的一级缓存

    • 同一个SqlSeesion但查询条件不同

    • 同一个SqlSession两次查询期间任意一次执行了任何一次增删改操作

    • 同一个SqlSession两次查询期间手动清空了缓存

 SqlSession sqlSession1= SqlSessionUtil.getSqlSession();
         CacheMapper cacheMapper1=sqlSession1.getMapper(CacheMapper.class);
         Emp emp=cacheMapper1.getEmpById(1);
         System.out.println(emp);
         //sqlSession1.clearCache();//清空SqlSession一级缓存
         cacheMapper1.InsertEmp(new Emp(null,"小黑",25,"男"));
 ​
         Emp emp2=cacheMapper1.getEmpById(1);
         System.out.println(emp2);
 ​
         SqlSession sqlSession2= SqlSessionUtil.getSqlSession();
         CacheMapper cacheMapper2=sqlSession2.getMapper(CacheMapper.class);
         Emp emp3=cacheMapper2.getEmpById(1);
         System.out.println(emp3);

二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询结果会被缓存;此后再次执行相同的查询语句时,结果就会从缓存中获取

开启条件:

  1. 在核心配置文件中,设置全局属性cacheEnabled=“true”,默认为true,无需设置

  2. 在映射文件中设置标签<cache/>

  3. 二级缓存必须在SqlSession关闭或提交后有效(即一级缓存失效后)

  4. 查询的数据所转换的实体类型必须实现序列化的接口

     //实现序列化接口
     public class Emp implements Serializable

使二级缓存失效:

  • 两次查询间执行了任意的增删改,会使一级和二级缓存同时失效

 public void testCache() throws IOException {
         InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
         SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(is);
         SqlSession sqlSession1=sessionFactory.openSession(true);
         CacheMapper mapper1=sqlSession1.getMapper(CacheMapper.class);
         Emp emp1=mapper1.getEmpById(2);
         System.out.println(emp1);
         sqlSession1.close();
         SqlSession sqlSession2=sessionFactory.openSession(true);
         CacheMapper mapper2=sqlSession2.getMapper(CacheMapper.class);
         Emp emp2=mapper2.getEmpById(2);
         System.out.println(emp2);
         sqlSession2.close();
    }

缓存查询顺序

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出的数据,可以直接使用。

如二级缓存没有,再查询一级缓存,如一级缓存也没有,则查询数据库。

SqlSession关闭后,一级缓存的数据会写入二级缓存

MyBatis的逆向工程

正向:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的

逆向:先创建数据库表,由框架负责根据数据库表,反向生成如下资源

  • Java实体类

  • Mapper接口

  • Mapper映射文件

创建逆向工程的步骤

  1. 添加依赖和插件

     <!--控制Maven在构建过程中相关配置-->
         <build>
             <plugins>
                 <!--具体插件,逆向工程的操作十一构建过程中插件形式出现的-->
                 <plugin>
                     <groupId>org.mybatis.generator</groupId>
                     <artifactId>mybatis-generator-maven-plugin</artifactId>
                     <version>1.3.0</version>
                     <!--插件的依赖-->
                     <dependencies>
                         <dependency>
                             <groupId>org.mybatis.generator</groupId>
                             <artifactId>mybatis-generator-core</artifactId>
                             <version>1.3.2</version>
                         </dependency>
                         <!--mysql驱动-->
                         <dependency>
                             <groupId>mysql</groupId>
                             <artifactId>mysql-connector-java</artifactId>
                             <version>8.0.13</version>
                         </dependency>
                     </dependencies>
                 </plugin>
             </plugins>
         </build>
  2. 创建Mybatis核心配置文件

  3. 创建逆向工程的配置文件

    文件名必须是:generatorConfig.xml

     <?xml version="1.0" encoding="UTF-8"?>
     <!DOCTYPE generatorConfiguration
             PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
             "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
     <generatorConfiguration>
     ​
         <!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包 -->
         <!--<classPathEntry location="D:\maven-warehouse\repository\mysql\mysql-connector-java\5.1.47\mysql-connector-java-5.1.47.jar"/>-->
         <!-- <classPathEntry location="D:\maven-warehouse\repository\mysql\mysql-connector-java\8.0.17\mysql-connector-java-8.0.17.jar"/> -->
     ​
         <!--
             targetRuntime:执行生成的逆向工程的版本
                 MyBatis3:生成带条件的CRUD
                 MyBatis3Simple:生成基本的CRUD
         -->
         <context id="DB2Tables"  targetRuntime="MyBatis3">
             <!-- 数据库连接驱动类,URL,用户名、密码 -->
             <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                             connectionURL="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC"
                             userId="root"
                             password="123456">
             </jdbcConnection>
             <!--JavaBean的生成策略-->
             <javaModelGenerator targetPackage="com.zwb.pojo" targetProject=".\src\main\java">
                 <property name="enableSubPackages" value="true"/>
                 <property name="trimStrings" value="true"/>
             </javaModelGenerator>
             <!-- 生成xml映射文件:包名(targetPackage)、位置(targetProject) -->
             <sqlMapGenerator targetPackage="com.zwb.mapper" targetProject=".\src\main\resources">
                 <property name="enableSubPackages" value="true"/>
             </sqlMapGenerator>
             <!-- 生成mapper接口:包名(targetPackage)、位置(targetProject) -->
             <javaClientGenerator type="XMLMAPPER" targetPackage="com.zwb.mapper" targetProject=".\src\main\java">
                 <property name="enableSubPackages" value="true"/>
             </javaClientGenerator>
             <!--
                 逆向分析表
                 tableName设置为*,可以对应所有表,此时不写domainObjectName
                 domainObjectName属性指定生成的实体类类名
              -->
             <table tableName="t_emp" domainObjectName="Emp"/>
             <table tableName="t_dept" domainObjectName="Dept"/>
         </context>
     </generatorConfiguration>
  4. 执行插件generate

使用

  @Test
     public void testMBG(){
         SqlSession sqlSession= SqlSessionUtil.getSqlSession();
         EmpMapper mapper=sqlSession.getMapper(EmpMapper.class);
         //根据id查询数据
         Emp emp=mapper.selectByPrimaryKey(1);
         System.out.println(emp);
         //查询所有数据
         //List<Emp> list=mapper.selectByExample(null);
         //根据条件查询数据
         /*EmpExample example=new EmpExample();
         example.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThan(20);
         example.or().andGenderEqualTo("男");
         List<Emp> list=mapper.selectByExample(example);
         for (Emp emp1 : list) {
             System.out.println(emp1);
         }*/
         emp=new Emp(1,"小黑子",null,"男");
         //测试普通修改
         //mapper.updateByPrimaryKey(emp);
         //选择性修改
         mapper.updateByPrimaryKeySelective(emp);
    }

逆向工程只能对单表使用

分页插件

limit index,pageSize index:当前页的起始索引 index=(pageNum-1)*pageSize pageSize:每页显示的条数

count:总记录数 totalPage:总页数 totalPage=count/pageSize

if(count%pageSize!=0){ totalPage++; }

 

使用步骤

  1. 添加依赖

     <!--分页插件依赖-->
             <dependency>
                 <groupId>com.github.pagehelper</groupId>
                 <artifactId>pagehelper</artifactId>
                 <version>5.2.0</version>
             </dependency>
  2. 配置分页插件

    在核心配置文件中配置插件

     <plugins>
             <!--设置分页插件-->
             <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
         </plugins>

插件的使用

  1. 在查询功能前使用PageHelper.startPage(int pageNum,int pageSize)开启分页功能

    pageNum:当前页页码

    pageSize:每页显示的条数

  @Test
     public void testPage(){
         SqlSession sqlSession= SqlSessionUtil.getSqlSession();
         EmpMapper mapper=sqlSession.getMapper(EmpMapper.class);
         //查询功能之前开启分页
         Page<Object> page=PageHelper.startPage(1,4);
         List<Emp> list=mapper.selectByExample(null);
         //查询功能之后可以获取分页相关的所有数据
         PageInfo<Emp> pageInfo=new PageInfo<>(list,5);
         for (Emp emp : list) {
             System.out.println(emp);
        }
         System.out.println(page);
         System.out.println(pageInfo);
    }

pageNum:当前页的页码

pageSize:每页显示的条数

size:当前页显示的真实条数

total:总记录数

pages:总页数

prePage:上一页的页码

nextPage:下一页的页码

isFirstPage/ isLastPage:是否为最初/末页

hasPreviousPag/hasNextPage:是否存在上/下一页

navigatePages:导航分页的页码数

navigatepageNums:导航分页的页码[1, 2, 3, 4, 5]

标签:mapper,映射,记录,查询,学习,sqlSession,emp,Mybatis,id
From: https://www.cnblogs.com/H-MADAO/p/17124304.html

相关文章

  • SM30检查 新建数据 修改数据自动带出默认值 以及根据SM30表修改记录检查 搜索帮助
    表维护创建好后将相应字段设置为不可输入设置对应的事件FORM程序   本需求是根据表维护创建修改自动带出日期事件用户名同时对维护内容校验Total表会存表维......
  • 记录常用的几个函数
    1、useMemoizedFn作用:记住某个函数,并且保证函数地址永远不会改变,可代替useCallback;constfoo=useMemoizedFn(()=>{console.log('test')});2、forwardRef作用:会创......
  • 【学习笔记】多项式学习笔记4:生成函数
    参考资料:OI-Wiki、APJ'spdf、学长的课件生成函数\(\text{GF(GeneratingFunction)}\)定义定义一个数列\(\{a_n\}\)的生成函数(或母函数)\(F(x)\)为:\[F(x)=\sum_{i\g......
  • MyBatis-Plus通用Iservice 方法详解
    publicinterfaceIService<T>{/***默认批次提交数量*/intDEFAULT_BATCH_SIZE=1000;/***插入一条记录(选择字段,策略插入)*......
  • c++学习7 指针与数组
    一二维数组与数组指针的关系二维数组名,代表的是第0行的行地址,“+1”是跳过一个行。而取“*”的话,则是在当前行地址基础上再取列地址,那么如果我们再取一个“*”呢?就会......
  • 第二次学习记录1
    第二次学习记录这个作业属于哪个课程班级链接这个作业要求在哪里作业要求链接这个作业的目标学习总结《计算机导论》这门课程的知识一、个人github主......
  • go爬虫学习
    1、使用http库本人使用http库封装了Post请求和Get请求,并且封装成MyHttp库使用,可设置代理和请求头,返回响应包主体Myhttp.gopackageMyHttpimport( "fmt" "io/ioutil......
  • 记录--『uni-app、小程序』蓝牙连接、读写数据全过程
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助本文简介这是一次真实的蓝牙收发数据的全过程讲解。本文使用uni-app+Vue3的方式进行开发,以手机app......
  • python的学习之路Day4
    2023.2.15Day42023.2.15Day4今日内容概要主题:数据类型(先熟悉)字符串列表字典布尔元组集合与用户交互基本运算符今日内容详细字符串str#用来记录描述性......
  • 学习python第三天
    今日内容概要pycharm软件的基本使用python的注释语法变量与常量python的底层优化垃圾回收机制数据类型整型浮点型今日内容详细pycharm软件的基本使用下载......