MyBatis学习(二)

MyBaits开发DAO的方法

1、原始的DAO开发

  • 程序员需要写dao接口和dao实现类。
  • 需要向dao实现类中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession
  • 测试案例

    映射文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 
    注意:使用mapper代理方法开发,namespace有特殊重要的作用
    -->
      <mapper namespace="test">
      
          <!-- 在 映射文件中配置很多sql语句 -->
        <!-- 需求:通过id查询角色表的记录 -->
        <!-- 通过 select执行数据库查询
        id:标识 映射文件中的 sql
        将sql语句封装到mappedStatement对象中,所以将id称为statement的id
        parameterType:指定输入 参数的类型,这里指定Integer型 
        #{}表示一个占位符号
        #{id}:其中的id表示接收输入 的参数,参数名称就是id,如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称
        
        resultType:指定sql输出结果 的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。
         -->
          
          <select id="getRole" parameterType="java.lang.Integer" resultType="Role">
              SELECT id , role_name as roleName , note FROM t_role WHERE id = #{value}
          </select>
          
          <!-- 根据note模糊查询角色信息,可能返回多条
        resultType:指定就是单条记录所映射的java对象 类型
        ${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中。
        使用${}拼接sql,引起 sql注入
        ${value}:接收输入 参数的内容,如果传入类型是简单类型,${}中只能使用value
         -->
          <select id="getRoles" parameterType="java.lang.String" resultType="Role">
              SELECT id , role_name AS roleName , note FROM t_role WHERE note LIKE '%${value}%'
          </select>
          
          <!-- 添加角色 
        parameterType:指定输入 参数类型是pojo(包括 角色信息)
        #{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值
        -->
          <insert id="insertRole" parameterType="Role">
              <!-- 
            将插入数据的主键返回,返回到role对象中
            
            SELECT LAST_INSERT_ID():得到刚insert进去记录的主键值,只适用与自增主键
            
            keyProperty:将查询到主键值设置到parameterType指定的对象的哪个属性
            order:SELECT LAST_INSERT_ID()执行顺序,相对于insert语句来说它的执行顺序
            resultType:指定SELECT LAST_INSERT_ID()的结果类型
             -->
              <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
                  SELECT LAST_INSERT_ID()
              </selectKey>
              INSERT INTO t_role(role_name, note) VALUES (#{roleName},#{note})
              
              <!-- 
            使用mysql的uuid()生成主键
            执行过程:
            首先通过uuid()得到主键,将主键设置到role对象的id属性中
            其次在insert执行时,从role对象中取出id属性值
             -->
              <!-- 
              <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
                  SELECT UUID()
              </selectKey>
              INSERT INTO t_role(id, role_name, note) VALUES (#{id},#{roleName},#{note}) -->
              
          </insert>
          <!-- 根据id删除角色-->
          <delete id="deleteRole" parameterType="java.lang.Integer" >
              DELETE FROM t_role WHERE id = #{value}
          </delete>
          
          
        <!-- 根据id更新角色
        分析:
        需要传入角色的id
        需要传入角色的更新信息
        parameterType指定role对象,包括 id和更新信息,注意:id必须存在
        #{id}:从输入 role+对象中获取id属性值
         -->
          <update id="updateRole" parameterType="Role" >
              UPDATE t_role SET role_name = #{roleName} , note=#{note} WHERE id = #{id}
          </update>
          
      </mapper>

    namespace此时为test

    dao接口:

    package ecut.access.dao;
    
    import java.util.List;
    
    import ecut.access.po.Role;
    
    public interface RoleDao {
        
        //根据id获取角色
        public Role getRole(Integer id) throws Exception ;
        
        // 根据note模糊查询角色列表
        public List<Role> getRoles(String note )  throws Exception ;
        
        //添加角色信息
        public int insertRole(Role r)  throws Exception ;
        
        //根据id删除角色信息
        public int deleteRole(Integer id)  throws Exception ;
        
        //更新角色信息
        public int updateRole(Role  r )  throws Exception ;
        
    }
    
    

    最好抛出异常,更好的将消息打印出来

    dao接口的实现类:

    package ecut.access.dao;
    
    import java.util.List;
    
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    
    import ecut.access.po.Role;
    
    public class RoleDaoImpl implements RoleDao{
        
        public SqlSessionFactory factory;
        
        // 需要向dao实现类中注入SqlSessionFactory
        // 这里通过构造方法注入
        public RoleDaoImpl(SqlSessionFactory factory){
            this.factory = factory;
        }
    
        @Override
        public Role getRole(Integer id) throws Exception {
            SqlSession session = factory.openSession();
            //执行查询操作
            Role role = session.selectOne("test.getRole", id);
            // 释放资源
            session.close();
            return role;
        }
    
        @Override
        public List<Role> getRoles(String note) throws Exception {
            SqlSession session = factory.openSession();
            //执行模糊查询操作
            List<Role> roles = session.selectList("test.getRoles", note);
            // 释放资源
            session.close();
            return roles;
        }
    
        @Override
        public int insertRole(Role r) throws Exception {
            SqlSession session = factory.openSession();
            //执行插入操作
            session.insert("test.insertRole", r);
            //提交事务
            session.commit();
            // 释放资源
            session.close();
            return 0;
        }
    
        @Override
        public int deleteRole(Integer id) throws Exception {
            SqlSession session = factory.openSession();
            //执行删除操作
            int i = session.delete("test.deleteRole", id);
            //提交事务
            session.commit();
            // 释放资源
            session.close();
            return i;
        }
    
        @Override
        public int updateRole(Role r) throws Exception {
            SqlSession session = factory.openSession();
            //执行更新操作
            session.update("test.updateRole", r);
            //提交事务
            session.commit();
            // 释放资源
            session.close();
            return 0;
        }
    
    }

    SqlSession是线程不安全的,在SqlSesion实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。因此SqlSession最佳应用场合在方法体内,定义成局部变量使用。

     测试类:

    package ecut.access.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Before;
    import org.junit.Test;
    
    import ecut.access.dao.RoleDao;
    import ecut.access.dao.RoleDaoImpl;
    import ecut.access.po.Role;
    
    public class RoleDaoImplTest {
        
        private SqlSessionFactory factory;
    
        @Before
        public  void init() throws IOException {
            // mybatis配置文件
            String resource = "ecut/access/mybaits-config.xml";
            // 得到配置文件流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 创建会话工厂,传入mybatis的配置文件信息
            factory = new SqlSessionFactoryBuilder().build(inputStream);
            // 通过工厂得到SqlSession
        }
    
        @Test
        public void testGetRole() throws Exception {
            //创建RoleDao对象
            RoleDao roleDao = new RoleDaoImpl(factory);
            //调用RoleDao方法
            Role role = roleDao.getRole(1);
            System.out.println(role);
            
            
        }
    
        @Test
        public void testGetRoles() throws Exception {
            RoleDao roleDao = new RoleDaoImpl(factory);
            List<Role> roles = roleDao.getRoles("火影");
            System.out.println(roles);
        }
    
        @Test
        public void testInsertRole() throws Exception {
            RoleDao roleDao = new RoleDaoImpl(factory);
            Role role = new Role();
            role.setNote("火影忍者");
            role.setRoleName("小樱");
            roleDao.insertRole(role);
        }
    
        @Test
        public void testDeleteRole() throws Exception {
            RoleDao roleDao = new RoleDaoImpl(factory);
            roleDao.deleteRole(4);
            
        }
    
        @Test
        public void testUpdateRole() throws Exception {
            RoleDao roleDao = new RoleDaoImpl(factory);
            Role role = new Role();
            role.setId(3);
            role.setNote("火影忍者");
            role.setRoleName("小樱");
            roleDao.updateRole(role);
            
        }
    
    }
  • 原始dao开发所存在的问题

    dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。

    调用sqlsession方法时将statement的id硬编码了

    调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。

2、mapper代理的方法

  • 程序员还需要编写mapper.xml映射文件
  • 程序员编写mapper接口需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类代理对象
  • 开发规范

    在mapper.xml中namespace等于mapper接口地址

    <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 
              注意:使用mapper代理方法开发,namespace有特殊重要的作用-->
      <mapper namespace="ecut.access.mapper.RoleMapper">

    mapper.java接口中的方法名和mapper.xml中statement的id一致

    mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致

    mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致

  • 测试案例

    mapper接口:

    package ecut.access.mapper;
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Param;
    
    import ecut.access.po.Role;
    
    public interface RoleMapper {
        
        //根据id获取角色
        public Role getRole(Integer id) throws Exception ;
        
        // 根据note模糊查询角色列表
        public List<Role> getRoles(String note )  throws Exception ;
        
        //根据note和roleName查询
        public List<Role> getRolesByNameAndNote(@Param("note") String note ,@Param("roleName")String roleName);
        
        //根据一组id获取角色
        public List<Role> getRolesByIds(List<Integer> ids);
        
        //添加角色信息
        public int insertRole(Role r)  throws Exception ;
        
        //根据id删除角色信息
        public int deleteRole(Integer id)  throws Exception ;
        
        //更新角色信息
        public int updateRole(Role  r )  throws Exception ;
        
    }

    mapper配置文件:修改Role.xml中的namespace改为接口的地址

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 
              注意:使用mapper代理方法开发,namespace有特殊重要的作用-->
      <mapper namespace="ecut.access.mapper.RoleMapper">
      
          <!-- 定义resultMap
        将id , role_name , note FROM t_role  和Role类中的属性作一个映射关系
        
        type:resultMap最终映射的java对象类型,可以使用别名
        id:对resultMap的唯一标识
         -->
         <resultMap type="role" id="roleResultMap">
             <!-- id表示查询结果集中唯一标识 
             column:查询出来的列名
             property:type指定的pojo类型中的属性名
             最终resultMap对column和property作一个映射关系 (对应关系)
             -->
             <id column="id" property="id"/>
             <!-- 
             result:对普通名映射定义
             column:查询出来的列名
             property:type指定的pojo类型中的属性名
             最终resultMap对column和property作一个映射关系 (对应关系)
              -->
             <result column="role_name" property="roleName"/>
             <result column="note" property="note"/>
         </resultMap>
         
          <!-- 定义sql片段
        id:sql片段的唯 一标识
        
        经验:是基于单表来定义sql片段,这样话这个sql片段可重用性才高
        在sql片段中不要包括 where
         -->
          <sql id="query_role_where">
            <if test="note != null and note != ''">
                  And note LIKE CONCAT('%',#{note},'%') 
              </if>
              <if test="roleName  != null and roleName != ''">
                  AND role_name LIKE CONCAT('%',#{roleName},'%')
              </if>
          </sql>
      
          <!-- 在 映射文件中配置很多sql语句 -->
        <!-- 需求:通过id查询角色表的记录 -->
        <!-- 通过 select执行数据库查询
        id:标识 映射文件中的 sql
        将sql语句封装到mappedStatement对象中,所以将id称为statement的id
        parameterType:指定输入 参数的类型,这里指定Integer型 
        #{}表示一个占位符号
        #{id}:其中的id表示接收输入 的参数,参数名称就是id,如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称
        
        resultType:指定sql输出结果 的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。
         -->
          
      <!--     <select id="getRole" parameterType="java.lang.Integer" resultType="Role">
              SELECT id , role_name as roleName , note FROM t_role WHERE id = #{value}
          </select> -->
          
          <select id="getRole" parameterType="int" resultMap="roleResultMap">
              SELECT * FROM t_role WHERE id = #{value}
          </select>
          
          
          <!-- 根据note模糊查询角色信息,可能返回多条
        resultType:指定就是单条记录所映射的java对象 类型
        ${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中。
        使用${}拼接sql,引起 sql注入
        ${value}:接收输入 参数的内容,如果传入类型是简单类型,${}中只能使用value
         -->
          <select id="getRoles" parameterType="java.lang.String" resultType="Role">
              SELECT id , role_name AS roleName , note FROM t_role WHERE note LIKE '%${value}%'
          </select>
          
          <!-- 角色信息综合查询  -->
          <!-- <select id="getRolesByNameAndNote" resultMap="roleResultMap">
              SELECT * FROM t_role 
              WHERE 1=1
              <if test="note != null and note != ''">
                  And note LIKE CONCAT('%',#{note},'%') 
              </if>
              <if test="roleName  != null and roleName != ''">
                  AND role_name LIKE CONCAT('%',#{roleName},'%')
              </if>
          </select> -->
          
          <!-- <select id="getRolesByNameAndNote" resultMap="roleResultMap">
              SELECT * FROM t_role 
              where可以自动去掉条件中的第一个and
              <where>
                  <if test="note != null and note != ''">
                      And note LIKE CONCAT('%',#{note},'%') 
                  </if>
                  <if test="roleName  != null and roleName != ''">
                      AND role_name LIKE CONCAT('%',#{roleName},'%')
                  </if>
              </where>
          </select>  -->
          
          
          <select id="getRolesByNameAndNote" resultMap="roleResultMap">
              SELECT * FROM t_role 
              <!-- 引用sql片段 的id,如果refid指定的id不在本mapper文件中,需要前边加namespace -->
              <where>
                  <include refid="query_role_where"></include>
            <!-- 在这里还可以引用其它的sql片段  -->
              </where>
          </select> 
          <!-- 使用 foreach遍历传入ids
                collection:指定输入 对象中集合属性
                item:每个遍历生成对象中
                open:开始遍历时拼接的串
                close:结束遍历时拼接的串
                separator:遍历的两个对象中需要拼接的串
                 -->
        <!-- 使用实现下边的sql拼接:AND (id=1 OR id=10 OR id=16) -->
          <!-- <select id="getRolesByIds" parameterType="java.util.List" resultMap="roleResultMap">
              SELECT * FROM t_role
              <where>
                  <foreach collection="list" item="item_id" open="AND (" close=")" separator="OR" >
                      id=#{item_id}
                  </foreach>
              </where>
          </select> -->
        
        <!-- 实现  “ and id IN(1,10,16)”拼接 -->
        <select id="getRolesByIds" parameterType="java.util.List" resultMap="roleResultMap">
              SELECT * FROM t_role
              <where>
                  <foreach collection="list" item="item_id" open="AND id IN (" close=")" separator="," >
                      #{item_id}
                  </foreach>
              </where>
          </select>
          
          <!-- 添加角色 
        parameterType:指定输入 参数类型是pojo(包括 角色信息)
        #{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值
        -->
          <insert id="insertRole" parameterType="Role">
              <!-- 
            将插入数据的主键返回,返回到role对象中
            
            SELECT LAST_INSERT_ID():得到刚insert进去记录的主键值,只适用与自增主键
            
            keyProperty:将查询到主键值设置到parameterType指定的对象的哪个属性
            order:SELECT LAST_INSERT_ID()执行顺序,相对于insert语句来说它的执行顺序
            resultType:指定SELECT LAST_INSERT_ID()的结果类型
             -->
              <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
                  SELECT LAST_INSERT_ID()
              </selectKey>
              INSERT INTO t_role(role_name, note) VALUES (#{roleName},#{note})
              
              <!-- 
            使用mysql的uuid()生成主键
            执行过程:
            首先通过uuid()得到主键,将主键设置到role对象的id属性中
            其次在insert执行时,从role对象中取出id属性值
             -->
              <!-- 
              <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
                  SELECT UUID()
              </selectKey>
              INSERT INTO t_role(id, role_name, note) VALUES (#{id},#{roleName},#{note}) -->
              
          </insert>
          <!-- 根据id删除角色-->
          <delete id="deleteRole" parameterType="java.lang.Integer" >
              DELETE FROM t_role WHERE id = #{value}
          </delete>
          
          
        <!-- 根据id更新角色
        分析:
        需要传入角色的id
        需要传入角色的更新信息
        parameterType指定role对象,包括 id和更新信息,注意:id必须存在
        #{id}:从输入 role+对象中获取id属性值
         -->
          <update id="updateRole" parameterType="Role" >
              UPDATE t_role SET role_name = #{roleName} , note=#{note} WHERE id = #{id}
          </update>
          
      </mapper>

    修改mybaits配置文件中对映射文件的相关引用

    测试类:

    package ecut.access.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    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.Before;
    import org.junit.Test;
    
    import ecut.access.mapper.RoleMapper;
    import ecut.access.po.Role;
    
    public class RoleMapperTest {
        
        private SqlSessionFactory factory;
    
        
        @Before
        public  void init() throws IOException {
            // mybatis配置文件
            String resource = "ecut/access/mybaits-config.xml";
            // 得到配置文件流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 创建会话工厂,传入mybatis的配置文件信息
            factory = new SqlSessionFactoryBuilder().build(inputStream);
            // 通过工厂得到SqlSession
        }
    
        @Test
        public void testGetRole() throws Exception{
            SqlSession session = factory.openSession();
            //创建RoleMapper对象,mybaits自动生成的mapper代理对象
            RoleMapper roleMapper = session.getMapper(RoleMapper.class);
            //class com.sun.proxy.$Proxy6,roleMapper代理对象
            System.out.println(roleMapper.getClass());
            Role role = roleMapper.getRole(1);
            System.out.println(role);
        }
        
     
        @Test
        public void testGetRoles() throws Exception{
            SqlSession session = factory.openSession();
            //创建RoleMapper对象,mybaits自动生成的mapper代理对象
            RoleMapper roleMapper = session.getMapper(RoleMapper.class);
            List<Role> roles = roleMapper.getRoles("火影");
            System.out.println(roles);
        }
    
        @Test
        public void testGetRolesByNameAndNote() throws Exception{
            SqlSession session = factory.openSession();
            //创建RoleMapper对象,mybaits自动生成的mapper代理对象
            RoleMapper roleMapper = session.getMapper(RoleMapper.class);
            //由于这里使用动态sql,如果不设置某个值,条件不会拼接在sql中
            List<Role> roles = roleMapper.getRolesByNameAndNote("火影","");
            System.out.println(roles);
        }
        
        
    
        @Test
        public void testGetRolesByIds() throws Exception{
            SqlSession session = factory.openSession();
            //创建RoleMapper对象,mybaits自动生成的mapper代理对象
            RoleMapper roleMapper = session.getMapper(RoleMapper.class);
            List<Integer> ids = new ArrayList<Integer>();
            ids.add(1);
            ids.add(2);
            ids.add(3);
            List<Role> roles = roleMapper.getRolesByIds(ids);
            System.out.println(roles);
        }
    
        
        @Test
        public void testInsertRole() throws Exception{
            SqlSession session = factory.openSession();
            //创建RoleMapper对象,mybaits自动生成的mapper代理对象
            RoleMapper roleMapper = session.getMapper(RoleMapper.class);
            Role role = new Role();
            role.setNote("火影忍者");
            role.setRoleName("小樱");
            roleMapper.insertRole(role);
            session.commit();
        }
    
        @Test
        public void testDeleteRole() throws Exception{
            SqlSession session = factory.openSession();
            //创建RoleMapper对象,mybaits自动生成的mapper代理对象
            RoleMapper roleMapper = session.getMapper(RoleMapper.class);
            roleMapper.deleteRole(4);
            session.commit();
        }
    
        @Test
        public void testUpdateRole() throws Exception{
            SqlSession session = factory.openSession();
            //创建RoleMapper对象,mybaits自动生成的mapper代理对象
            RoleMapper roleMapper = session.getMapper(RoleMapper.class);
            Role role = new Role();
            role.setId(3);
            role.setNote("火影忍者");
            role.setRoleName("小樱");
            roleMapper.updateRole(role);
            session.commit();
        }
    
    }

MyBaits的配置文件

1、properties属性

  • 将数据库连接参数单独配置在jdbc.properties中,只需要在mybaits-config.xml中加载jdbc.properties的属性值。
  • 在mybaits-config.xml中就不需要对数据库连接参数硬编码。
  • 将数据库连接参数只配置在jdbc.properties(得放在源包下)中,原因:方便对参数进行统一管理,其它xml可以引用该jdbc.properties。
  • 测试案例

    jdbc.properties

    jdbc.url = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF8
    jdbc.driver = com.mysql.jdbc.Driver
    jdbc.user = root
    jdbc.password = 123456

    mybaits-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="jdbc.properties">
            <!--properties中还可以配置一些属性名和属性值  -->
            <!-- <property name="jdbc.driver" value=""/> -->
        </properties>
        <!-- 全局配置参数,需要时再设置 -->
      
        <environments default="development">
        
            <environment id="development">
            <!-- 使用jdbc事务管理,事务控制由mybatis-->
                <transactionManager type="JDBC" />
                <!-- 数据库连接池,由mybatis管理-->
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}" />
                    <property name="url" value="${jdbc.url}" />
                    <property name="username" value="${jdbc.user}" />
                    <property name="password" value="${jdbc.password}" />
                </dataSource>
            </environment>
    
        </environments>
        <!-- 加载 映射文件 -->
        <mappers>
            
             <!--通过resource方法一次加载一个映射文件 -->
            <!-- <mapper resource="ecut/access/dao/Role.xml"/> -->
            <mapper resource="ecut/access/mapper/RoleMapper.xml"/>
        
        </mappers>
        
    </configuration>

    不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中。在properties文件中定义属性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX

2、settings全局参数配置

  • mybatis框架在运行时可以调整一些运行参数。比如:开启二级缓存、开启延迟加载。。
  •  全局参数将会影响mybatis的运行行为

3、typeAliases(别名)

  • 在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。
  • 如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。
  • 默认的别名参照org.apache.ibatis.type.TypeAliasRegistry类中的相关方法
    public TypeAliasRegistry() {
        registerAlias("string", String.class);
    
        registerAlias("byte", Byte.class);
        registerAlias("long", Long.class);
        registerAlias("short", Short.class);
        registerAlias("int", Integer.class);
        registerAlias("integer", Integer.class);
        registerAlias("double", Double.class);
        registerAlias("float", Float.class);
        registerAlias("boolean", Boolean.class);
    
        registerAlias("byte[]", Byte[].class);
        registerAlias("long[]", Long[].class);
        registerAlias("short[]", Short[].class);
        registerAlias("int[]", Integer[].class);
        registerAlias("integer[]", Integer[].class);
        registerAlias("double[]", Double[].class);
        registerAlias("float[]", Float[].class);
        registerAlias("boolean[]", Boolean[].class);
    
        registerAlias("_byte", byte.class);
        registerAlias("_long", long.class);
        registerAlias("_short", short.class);
        registerAlias("_int", int.class);
        registerAlias("_integer", int.class);
        registerAlias("_double", double.class);
        registerAlias("_float", float.class);
        registerAlias("_boolean", boolean.class);
    
        registerAlias("_byte[]", byte[].class);
        registerAlias("_long[]", long[].class);
        registerAlias("_short[]", short[].class);
        registerAlias("_int[]", int[].class);
        registerAlias("_integer[]", int[].class);
        registerAlias("_double[]", double[].class);
        registerAlias("_float[]", float[].class);
        registerAlias("_boolean[]", boolean[].class);
    
        registerAlias("date", Date.class);
        registerAlias("decimal", BigDecimal.class);
        registerAlias("bigdecimal", BigDecimal.class);
        registerAlias("biginteger", BigInteger.class);
        registerAlias("object", Object.class);
    
        registerAlias("date[]", Date[].class);
        registerAlias("decimal[]", BigDecimal[].class);
        registerAlias("bigdecimal[]", BigDecimal[].class);
        registerAlias("biginteger[]", BigInteger[].class);
        registerAlias("object[]", Object[].class);
    
        registerAlias("map", Map.class);
        registerAlias("hashmap", HashMap.class);
        registerAlias("list", List.class);
        registerAlias("arraylist", ArrayList.class);
        registerAlias("collection", Collection.class);
        registerAlias("iterator", Iterator.class);
    
        registerAlias("ResultSet", ResultSet.class);
      }
    查看代码
  • 单个自定义别名定义
    <!-- 别名定义 TypeAliasRegistry-->
        <typeAliases>
    
            <!-- 针对单个别名定义
            type:类型的路径
            alias:别名
             -->
            <typeAlias type="ecut.access.po.Role" alias="Role"/>
            
        </typeAliases>

    在映射文件就无需写Role类的全类名只需用Role代替

  • 批量别名定义
    <!-- 别名定义 TypeAliasRegistry-->
        <typeAliases>
        
            <!-- 批量别名定义 
            指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大写或小写都可以)
            -->
             <package name="ecut.access.po"/>
    </typeAliases>

3、typeHandler 类处理器

  • mybatis中通过typeHandlers完成jdbc类型和java类型的转换。通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义.
  • mybatis支持类型处理器(参考org.apache.ibatis.type.TypeHandlerRegistry类):
    类型处理器	        Java类型	                 JDBC类型
    BooleanTypeHandler 	Boolean,boolean 	任何兼容的布尔值
    ByteTypeHandler 	Byte,byte 	        任何兼容的数字或字节类型
    ShortTypeHandler 	Short,short 	        任何兼容的数字或短整型
    IntegerTypeHandler 	Integer,int 	        任何兼容的数字和整型
    LongTypeHandler 	Long,long 	        任何兼容的数字或长整型
    FloatTypeHandler 	Float,float 	        任何兼容的数字或单精度浮点型
    DoubleTypeHandler 	Double,double 	        任何兼容的数字或双精度浮点型
    BigDecimalTypeHandler 	BigDecimal 	       任何兼容的数字或十进制小数类型
    StringTypeHandler 	String 	                CHAR和VARCHAR类型
    ClobTypeHandler 	String 	                CLOB和LONGVARCHAR类型
    NStringTypeHandler 	String 	                NVARCHAR和NCHAR类型
    NClobTypeHandler 	String 	                NCLOB类型
    ByteArrayTypeHandler 	byte[] 	                任何兼容的字节流类型
    BlobTypeHandler 	byte[] 	                BLOB和LONGVARBINARY类型
    DateTypeHandler 	Date(java.util)	TIMESTAMP类型
    DateOnlyTypeHandler 	Date(java.util)	DATE类型
    TimeOnlyTypeHandler 	Date(java.util)	TIME类型
    SqlTimestampTypeHandler Timestamp(java.sql)	TIMESTAMP类型
    SqlDateTypeHandler 	Date(java.sql)	        DATE类型
    SqlTimeTypeHandler 	Time(java.sql)	        TIME类型
    ObjectTypeHandler 	任意	                其他或未指定类型
    EnumTypeHandler 	Enumeration类型	        VARCHAR-任何兼容的字符串类型,作为代码存储(而不是索引)。

4、映射配置文件

  • 通过resource加载单个配置文件
        <!-- 加载 映射文件 -->
        <mappers>
            
             <!--通过resource方法一次加载一个映射文件 -->
            <!-- <mapper resource="ecut/access/dao/Role.xml"/> -->
            <mapper resource="ecut/access/mapper/RoleMapper.xml"/>
        
        </mappers>
  • 通过mapper接口加载单个mapper
      <mappers>
            <!-- 通过mapper接口加载单个 映射文件
            遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中
            上边规范的前提是:使用的是mapper代理方法
             -->
             <mapper class="ecut.access.mapper.RoleMapper"/>
    </mappers>

    通过mapper接口加载单个 映射文件遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中。上边规范的前提是:使用的是mapper代理方法

  • 批量加载mapper(推荐使用)
    <!-- 加载 映射文件 -->
        <mappers>
             
             <!-- 批量加载mapper
            指定mapper接口的包名,mybatis自动扫描包下边所有mapper接口进行加载
            遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中
            上边规范的前提是:使用的是mapper代理方法
             -->
             <package name="ecut.access.mapper"/>
    </mappers>

    指定mapper接口的包名,mybatis自动扫描包下边所有mapper接口进行加载。遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中。上边规范的前提是:使用的是mapper代理方法

  • 直接在spring配置文件中进行映射配置

输入映射

1、#{}和${}

  • #{}表示一个占位符号,#{}接收输入参数,类型可以是简单类型,pojo、hashmap。
  • 如果接收简单类型,#{}中可以写成value或其它名称。
  • #{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值
  • ${}表示一个拼接符号,会引用sql注入,所以不建议使用${}。
  • ${}接收输入参数,类型可以是简单类型,pojo、hashmap。
  • 如果接收简单类型,${}中只能写成value。
  • ${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。

2、parameterType支持传入类型

  • 传递简单类型:可以使用在org.apache.ibatis.type.TypeAliasRegistry类中指定的默认别名
  • 传递POJO对象:Mybatis使用ognl表达式解析对象字段的值,在配置文件中输入参数名称则为POJO类中的getter方法中的名称
  • 传递POJO包装对象:mybatis底层通过ognl从pojo中获取属性值:#{user.username},user即是传入的包装对象的属性。
  • 传递hashmap:输入参数为hashmap的key,传递的map中的key和sql中解析的key不一致。没有报错,只是通过key获取值为空。

输出映射

1、resultType

  • 使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名或者是setter方法一致,该列才可以映射成功。
  • 如果查询出来的列名和pojo中的属性名或者setter全部不一致,没有创建pojo对象。
  • 只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
  • 测试案例

    映射文件:

        <!-- 根据note模糊查询角色信息,可能返回多条
        resultType:指定就是单条记录所映射的java对象 类型
        ${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中。
        使用${}拼接sql,引起 sql注入
        ${value}:接收输入 参数的内容,如果传入类型是简单类型,${}中只能使用value
         -->
          <select id="getRoles" parameterType="java.lang.String" resultType="Role">
              SELECT id , role_name AS roleName , note FROM t_role WHERE note LIKE '%${value}%'
          </select>

    接口类:

    package ecut.access.mapper;
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Param;
    
    import ecut.access.po.Role;
    
    public interface RoleMapper {
      // 根据note模糊查询角色列表
        public List<Role> getRoles(String note )  throws Exception ;
        
    }

    测试类:

    package ecut.access.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    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.Before;
    import org.junit.Test;
    
    import ecut.access.mapper.RoleMapper;
    import ecut.access.po.Role;
    
    public class RoleMapperTest {
        
        private SqlSessionFactory factory;
    
        
        @Before
        public  void init() throws IOException {
            // mybatis配置文件
            String resource = "ecut/access/mybaits-config.xml";
            // 得到配置文件流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 创建会话工厂,传入mybatis的配置文件信息
            factory = new SqlSessionFactoryBuilder().build(inputStream);
            // 通过工厂得到SqlSession
        }
    
        @Test
        public void testGetRoles() throws Exception{
            SqlSession session = factory.openSession();
            //创建RoleMapper对象,mybaits自动生成的mapper代理对象
            RoleMapper roleMapper = session.getMapper(RoleMapper.class);
            List<Role> roles = roleMapper.getRoles("火影");
            System.out.println(roles);
        }
    
    }

2、resultMap

  • 如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。
  • 基本步骤:定义resultMap、使用resultMap作为statement的输出映射类型
  • 测试案例:

    映射文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 
              注意:使用mapper代理方法开发,namespace有特殊重要的作用-->
      <mapper namespace="ecut.access.mapper.RoleMapper">
      
          <!-- 定义resultMap
        将id , role_name , note FROM t_role  和Role类中的属性作一个映射关系
        
        type:resultMap最终映射的java对象类型,可以使用别名
        id:对resultMap的唯一标识
         -->
         <resultMap type="role" id="roleResultMap">
             <!-- id表示查询结果集中唯一标识 
             column:查询出来的列名
             property:type指定的pojo类型中的属性名
             最终resultMap对column和property作一个映射关系 (对应关系)
             -->
             <id column="id" property="id"/>
             <!-- 
             result:对普通名映射定义
             column:查询出来的列名
             property:type指定的pojo类型中的属性名
             最终resultMap对column和property作一个映射关系 (对应关系)
              -->
             <result column="role_name" property="roleName"/>
             <result column="note" property="note"/>
         </resultMap>
         
      
          <!-- 在 映射文件中配置很多sql语句 -->
        <!-- 需求:通过id查询角色表的记录 -->
        <!-- 通过 select执行数据库查询
        id:标识 映射文件中的 sql
        将sql语句封装到mappedStatement对象中,所以将id称为statement的id
        parameterType:指定输入 参数的类型,这里指定Integer型 
        #{}表示一个占位符号
        #{id}:其中的id表示接收输入 的参数,参数名称就是id,如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称
        
        resultType:指定sql输出结果 的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。
         -->
          
      <!--     <select id="getRole" parameterType="java.lang.Integer" resultType="Role">
              SELECT id , role_name as roleName , note FROM t_role WHERE id = #{value}
          </select> -->
          
          <select id="getRole" parameterType="int" resultMap="roleResultMap">
              SELECT * FROM t_role WHERE id = #{value}
          </select>

    </mapper>

    接口类:

    package ecut.access.mapper;
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Param;
    
    import ecut.access.po.Role;
    
    public interface RoleMapper {
        
        //根据id获取角色
        public Role getRole(Integer id) throws Exception ;
        
        
    }

    测试类:

    package ecut.access.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    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.Before;
    import org.junit.Test;
    
    import ecut.access.mapper.RoleMapper;
    import ecut.access.po.Role;
    
    public class RoleMapperTest {
        
        private SqlSessionFactory factory;
    
        
        @Before
        public  void init() throws IOException {
            // mybatis配置文件
            String resource = "ecut/access/mybaits-config.xml";
            // 得到配置文件流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 创建会话工厂,传入mybatis的配置文件信息
            factory = new SqlSessionFactoryBuilder().build(inputStream);
            // 通过工厂得到SqlSession
        }
    
        @Test
        public void testGetRole() throws Exception{
            SqlSession session = factory.openSession();
            //创建RoleMapper对象,mybaits自动生成的mapper代理对象
            RoleMapper roleMapper = session.getMapper(RoleMapper.class);
            //class com.sun.proxy.$Proxy6,roleMapper代理对象
            System.out.println(roleMapper.getClass());
            Role role = roleMapper.getRole(1);
            System.out.println(role);
        }
        
    
    }

    使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。

动态SQL

1、mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装,这就是动态SQL。

2、if标签

    <select id="getRolesByNameAndNote" resultMap="roleResultMap">
          SELECT * FROM t_role 
          WHERE 1=1
          <if test="note != null and note != ''">
              And note LIKE CONCAT('%',#{note},'%') 
          </if>
          <if test="roleName  != null and roleName != ''">
              AND role_name LIKE CONCAT('%',#{roleName},'%')
          </if>
      </select>

通过where1=1以解决两个参数都非空and多余的问题,注意要做不等于空字符串校验。

3、where标签

    <select id="getRolesByNameAndNote" resultMap="roleResultMap">
          SELECT * FROM t_role 
          <!-- where可以自动去掉条件中的第一个and -->
          <where>
              <if test="note != null and note != ''">
                  And note LIKE CONCAT('%',#{note},'%') 
              </if>
              <if test="roleName  != null and roleName != ''">
                  AND role_name LIKE CONCAT('%',#{roleName},'%')
              </if>
          </where>
      </select> 

where标签可以自动去除第一个and

 4、SQL片段:可以将重复的sql片段提取出来,使用时用include引用即可,最终达到sql重用的目的,增加代码的复用性。

 接口类:

package ecut.access.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import ecut.access.po.Role;

public interface RoleMapper {
   //根据note和roleName查询
    public List<Role> getRolesByNameAndNote(@Param("note") String note ,@Param("roleName")String roleName);
  
}

映射文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  
  <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 
          注意:使用mapper代理方法开发,namespace有特殊重要的作用-->
  <mapper namespace="ecut.access.mapper.RoleMapper">
  
      <!-- 定义resultMap
    将id , role_name , note FROM t_role  和Role类中的属性作一个映射关系
    
    type:resultMap最终映射的java对象类型,可以使用别名
    id:对resultMap的唯一标识
     -->
     <resultMap type="role" id="roleResultMap">
         <!-- id表示查询结果集中唯一标识 
         column:查询出来的列名
         property:type指定的pojo类型中的属性名
         最终resultMap对column和property作一个映射关系 (对应关系)
         -->
         <id column="id" property="id"/>
         <!-- 
         result:对普通名映射定义
         column:查询出来的列名
         property:type指定的pojo类型中的属性名
         最终resultMap对column和property作一个映射关系 (对应关系)
          -->
         <result column="role_name" property="roleName"/>
         <result column="note" property="note"/>
     </resultMap>
     
      <!-- 定义sql片段
    id:sql片段的唯 一标识
    
    经验:是基于单表来定义sql片段,这样话这个sql片段可重用性才高
    在sql片段中不要包括 where
     -->
      <sql id="query_role_where">
        <if test="note != null and note != ''">
              And note LIKE CONCAT('%',#{note},'%') 
          </if>
          <if test="roleName  != null and roleName != ''">
              AND role_name LIKE CONCAT('%',#{roleName},'%')
          </if>
      </sql>
  
      <!-- 角色信息综合查询  -->
      <!-- <select id="getRolesByNameAndNote" resultMap="roleResultMap">
          SELECT * FROM t_role 
          WHERE 1=1
          <if test="note != null and note != ''">
              And note LIKE CONCAT('%',#{note},'%') 
          </if>
          <if test="roleName  != null and roleName != ''">
              AND role_name LIKE CONCAT('%',#{roleName},'%')
          </if>
      </select> -->
      
      <!-- <select id="getRolesByNameAndNote" resultMap="roleResultMap">
          SELECT * FROM t_role 
          where可以自动去掉条件中的第一个and
          <where>
              <if test="note != null and note != ''">
                  And note LIKE CONCAT('%',#{note},'%') 
              </if>
              <if test="roleName  != null and roleName != ''">
                  AND role_name LIKE CONCAT('%',#{roleName},'%')
              </if>
          </where>
      </select>  -->
      
      
      <select id="getRolesByNameAndNote" resultMap="roleResultMap">
          SELECT * FROM t_role 
          <!-- 引用sql片段 的id,如果refid指定的id不在本mapper文件中,需要前边加namespace -->
          <where>
              <include refid="query_role_where"></include>
        <!-- 在这里还可以引用其它的sql片段  -->
          </where>

      
  </mapper>

在sql片段中不要包括 where

测试类:

package ecut.access.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

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.Before;
import org.junit.Test;

import ecut.access.mapper.RoleMapper;
import ecut.access.po.Role;

public class RoleMapperTest {
    
    private SqlSessionFactory factory;

    
    @Before
    public  void init() throws IOException {
        // mybatis配置文件
        String resource = "ecut/access/mybaits-config.xml";
        // 得到配置文件流
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 创建会话工厂,传入mybatis的配置文件信息
        factory = new SqlSessionFactoryBuilder().build(inputStream);
        // 通过工厂得到SqlSession
    }

    @Test
    public void testGetRolesByNameAndNote() throws Exception{
        SqlSession session = factory.openSession();
        //创建RoleMapper对象,mybaits自动生成的mapper代理对象
        RoleMapper roleMapper = session.getMapper(RoleMapper.class);
        //由于这里使用动态sql,如果不设置某个值,条件不会拼接在sql中
        List<Role> roles = roleMapper.getRolesByNameAndNote("火影","");
        System.out.println(roles);
    }


}

5、foreach标签

接口类:

package ecut.access.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import ecut.access.po.Role;

public interface RoleMapper {
    
  //根据一组id获取角色
    public List<Role> getRolesByIds(List<Integer> ids);
    
}

映射文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  
  <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 
          注意:使用mapper代理方法开发,namespace有特殊重要的作用-->
  <mapper namespace="ecut.access.mapper.RoleMapper">
  
      <!-- 定义resultMap
    将id , role_name , note FROM t_role  和Role类中的属性作一个映射关系
    
    type:resultMap最终映射的java对象类型,可以使用别名
    id:对resultMap的唯一标识
     -->
     <resultMap type="role" id="roleResultMap">
         <!-- id表示查询结果集中唯一标识 
         column:查询出来的列名
         property:type指定的pojo类型中的属性名
         最终resultMap对column和property作一个映射关系 (对应关系)
         -->
         <id column="id" property="id"/>
         <!-- 
         result:对普通名映射定义
         column:查询出来的列名
         property:type指定的pojo类型中的属性名
         最终resultMap对column和property作一个映射关系 (对应关系)
          -->
         <result column="role_name" property="roleName"/>
         <result column="note" property="note"/>
     </resultMap>
     
      <!-- 定义sql片段
    id:sql片段的唯 一标识
    
    经验:是基于单表来定义sql片段,这样话这个sql片段可重用性才高
    在sql片段中不要包括 where
     -->
      <sql id="query_role_where">
        <if test="note != null and note != ''">
              And note LIKE CONCAT('%',#{note},'%') 
          </if>
          <if test="roleName  != null and roleName != ''">
              AND role_name LIKE CONCAT('%',#{roleName},'%')
          </if>
      </sql>
  

      <!-- 使用 foreach遍历传入ids
            collection:指定输入 对象中集合属性
            item:每个遍历生成对象中
            open:开始遍历时拼接的串
            close:结束遍历时拼接的串
            separator:遍历的两个对象中需要拼接的串
             -->
    <!-- 使用实现下边的sql拼接:AND (id=1 OR id=10 OR id=16) -->
      <!-- <select id="getRolesByIds" parameterType="java.util.List" resultMap="roleResultMap">
          SELECT * FROM t_role
          <where>
              <foreach collection="list" item="item_id" open="AND (" close=")" separator="OR" >
                  id=#{item_id}
              </foreach>
          </where>
      </select> -->
    
    <!-- 实现  “ and id IN(1,10,16)”拼接 -->
    <select id="getRolesByIds" parameterType="java.util.List" resultMap="roleResultMap">
          SELECT * FROM t_role
          <where>
              <foreach collection="list" item="item_id" open="AND id IN (" close=")" separator="," >
                  #{item_id}
              </foreach>
          </where>
      </select>

  </mapper>

向sql传递数组或List,mybatis使用foreach解析

  • item:每个遍历生成对象中
  • open:开始遍历时拼接的串
  • close:结束遍历时拼接的串
  • separator:遍历的两个对象中需要拼接的串
  •  collection:指定输入 对象中集合属性

collection的三种用法

  • 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
  • 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
  • 如果传入的参数是多个的时候,或者是以一个对象为参数,collection的属性值就要取你自己定义的名字了,不管是list类型还是array类型

测试类:

package ecut.access.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

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.Before;
import org.junit.Test;

import ecut.access.mapper.RoleMapper;
import ecut.access.po.Role;

public class RoleMapperTest {
    
    private SqlSessionFactory factory;

    
    @Before
    public  void init() throws IOException {
        // mybatis配置文件
        String resource = "ecut/access/mybaits-config.xml";
        // 得到配置文件流
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 创建会话工厂,传入mybatis的配置文件信息
        factory = new SqlSessionFactoryBuilder().build(inputStream);
        // 通过工厂得到SqlSession
    }



    @Test
    public void testGetRolesByIds() throws Exception{
        SqlSession session = factory.openSession();
        //创建RoleMapper对象,mybaits自动生成的mapper代理对象
        RoleMapper roleMapper = session.getMapper(RoleMapper.class);
        List<Integer> ids = new ArrayList<Integer>();
        ids.add(1);
        ids.add(2);
        ids.add(3);
        List<Role> roles = roleMapper.getRolesByIds(ids);
        System.out.println(roles);
    }


}

 如果在映射文件中collection写的是ids,就会抛出org.apache.ibatis.binding.BindingException: Parameter 'ids' not found. Available parameters are [collection, list]的异常,应该按照正确的传参来传递。

collection的三种用法

  • 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
  • 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
  • 如果传入的参数是多个的时候,或者是以一个对象为参数,collection的属性值就要取你自己定义的名字了,不管是list类型还是array类型

传递多个参数的方式

1、使用@Param注解如上面的测试案例,不需要对parameterType进行配置。

接口类:

package ecut.access.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import ecut.access.po.Role;

public interface RoleMapper {
   //根据note和roleName查询
    public List<Role> getRolesByNameAndNote(@Param("note") String note ,@Param("roleName")String roleName);
  
}

映射文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  
  <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 
          注意:使用mapper代理方法开发,namespace有特殊重要的作用-->
  <mapper namespace="ecut.access.mapper.RoleMapper">
  
      <!-- 定义resultMap
    将id , role_name , note FROM t_role  和Role类中的属性作一个映射关系
    
    type:resultMap最终映射的java对象类型,可以使用别名
    id:对resultMap的唯一标识
     -->
     <resultMap type="role" id="roleResultMap">
         <!-- id表示查询结果集中唯一标识 
         column:查询出来的列名
         property:type指定的pojo类型中的属性名
         最终resultMap对column和property作一个映射关系 (对应关系)
         -->
         <id column="id" property="id"/>
         <!-- 
         result:对普通名映射定义
         column:查询出来的列名
         property:type指定的pojo类型中的属性名
         最终resultMap对column和property作一个映射关系 (对应关系)
          -->
         <result column="role_name" property="roleName"/>
         <result column="note" property="note"/>
     </resultMap>
     
      <!-- 定义sql片段
    id:sql片段的唯 一标识
    
    经验:是基于单表来定义sql片段,这样话这个sql片段可重用性才高
    在sql片段中不要包括 where
     -->
      <sql id="query_role_where">
        <if test="note != null and note != ''">
              And note LIKE CONCAT('%',#{note},'%') 
          </if>
          <if test="roleName  != null and roleName != ''">
              AND role_name LIKE CONCAT('%',#{roleName},'%')
          </if>
      </sql>
  
      <!-- 角色信息综合查询  -->
      <!-- <select id="getRolesByNameAndNote" resultMap="roleResultMap">
          SELECT * FROM t_role 
          WHERE 1=1
          <if test="note != null and note != ''">
              And note LIKE CONCAT('%',#{note},'%') 
          </if>
          <if test="roleName  != null and roleName != ''">
              AND role_name LIKE CONCAT('%',#{roleName},'%')
          </if>
      </select> -->
      
      <!-- <select id="getRolesByNameAndNote" resultMap="roleResultMap">
          SELECT * FROM t_role 
          where可以自动去掉条件中的第一个and
          <where>
              <if test="note != null and note != ''">
                  And note LIKE CONCAT('%',#{note},'%') 
              </if>
              <if test="roleName  != null and roleName != ''">
                  AND role_name LIKE CONCAT('%',#{roleName},'%')
              </if>
          </where>
      </select>  -->
      
      
      <select id="getRolesByNameAndNote" resultMap="roleResultMap">
          SELECT * FROM t_role 
          <!-- 引用sql片段 的id,如果refid指定的id不在本mapper文件中,需要前边加namespace -->
          <where>
              <include refid="query_role_where"></include>
        <!-- 在这里还可以引用其它的sql片段  -->
          </where>

      
  </mapper>

2、使用索引方式,来指定想传入的参数,#{arg0}索引从0开始或者#{param1}索引从1开始,不需要对parameterType进行配置

接口类:

package ecut.access.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import ecut.access.po.Role;

public interface RoleMapper {
    
    //根据note和roleName查询

    public List<Role> getRolesByNameAndNote(String note ,String roleName);

}

映射文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  
  <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 
          注意:使用mapper代理方法开发,namespace有特殊重要的作用-->
  <mapper namespace="ecut.access.mapper.RoleMapper">
  
      <!-- 定义resultMap
    将id , role_name , note FROM t_role  和Role类中的属性作一个映射关系
    
    type:resultMap最终映射的java对象类型,可以使用别名
    id:对resultMap的唯一标识
     -->
     <resultMap type="role" id="roleResultMap">
         <!-- id表示查询结果集中唯一标识 
         column:查询出来的列名
         property:type指定的pojo类型中的属性名
         最终resultMap对column和property作一个映射关系 (对应关系)
         -->
         <id column="id" property="id"/>
         <!-- 
         result:对普通名映射定义
         column:查询出来的列名
         property:type指定的pojo类型中的属性名
         最终resultMap对column和property作一个映射关系 (对应关系)
          -->
         <result column="role_name" property="roleName"/>
         <result column="note" property="note"/>
     </resultMap>
     
      
     <select id="getRolesByNameAndNote" resultMap="roleResultMap">
          SELECT * FROM t_role 
          <where>
              <if test="arg0 != null and arg0 != ''">
                  And note LIKE CONCAT('%',#{arg0},'%') 
              </if>
              <if test="arg1  != null and arg1 != ''">
                  AND role_name LIKE CONCAT('%',#{arg1},'%')
              </if>
          </where>
      </select> 
      
      
  </mapper>

配置文件中如果用#{index}的方式配置会抛出org.apache.ibatis.binding.BindingException: Parameter '0' not found. Available parameters are [arg1, arg0, param1, param2]的异常,需要按照#{arg0}或者是#{param1}的方式来配置,#{arg0}索引从0开始或者#{param1}索引从1开始。如果要使用if标签需要将标签内的字段都替换为#{arg0}或者是#{param1}不然会抛出 org.apache.ibatis.binding.BindingException: Parameter 'note' not found. Available parameters are [arg1, arg0, param1, param2]异常,因为if标签的note找不到。

3、使用Map方式传递多个参数,map中的key的名字就是对应xml配置中#{}中使用的那个

4、使用POJO对象封装

5、使用List方式封装(参考foreach标签的案例)

转载请于明显处标明出处

https://www.cnblogs.com/AmyZheng/p/9356911.html

原文地址:https://www.cnblogs.com/AmyZheng/p/9356911.html