IBatis的使用

IBatis的使用

1、IBatis是什么

回顾之前前端访问后端的整个流程:

View ------ >Controller --------> Service ---------> DAO ------> 数据库

View :前端jsp/HTML

Controller:Servlet/SpringMVC

Service :Spring

DAO:jdbc/dbutils/jdbctemplate/mybatis

mybatis实际上就是 DAO层的一个解决方案

jdbc、dbutils、jdbcTemplate、Hibernate以及mybatis的对比:

JDBC:代码非常复杂、速度快

Hibernate:代码精简、缺点(速度慢)

dbutils、jdbcTemplate:不是框架 只是对jdbc的一个简单的封装而已

mybatis:他是属于效率处于JDBC和Hibernate之间

​ 他的代码的复杂度也是趋于 JDBC和Hibernate之间、 代码灵活

iBatis和mybatis之间的关系是什么?

ibatis是以前的叫法 mybatis是现在的叫法

2、iBatis能做什么

数据库的访问(CRUD)

整合缓存、还可以给类取别名、IBatis还提供了整合Spring的第三方的包

3、IBatis的简单的使用(一)(IBatis的数据不传参的问题)
3.1、导包
 <!--导包-->
    <!--下面就是iBatis的相关的包-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.6</version>
    </dependency>
    <!--mysql的驱动 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.6</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.5.10</version>
    </dependency>
    <!--日志门面-->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.6.1</version>
    </dependency>
    <!-- 单元测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12-beta-3</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
    </dependency>
  </dependencies>
3.2编写mybatis.xml配置文件

说明:配置文件的名字可以随意取

<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--这个文件的作用:是对mybatis的全局配置-->
<configuration>
    <!--
        environments:环境+s,说明可以配置等多个环境
        这里配置的环境是:数据库的连接信息
        default:如果配置了多个环境 默认使用哪一个环境
    -->
    <environments default="mysql">
        <!--配置一个环境:id:表示的是这个环境的名字
            逻辑意义上是可以随便写的
        -->
        <environment id="mysql">
            <!--配置的是事务的类型 ,默认配置JDBC就可以了  一般情况下使用的就是这个类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--这个配置的是数据源  这里你可以认为是固定写法-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
        <!--这里是可以配置多个环境的  要使用哪一个环境那么就就配置上面的default就可以了 -->
        <environment id="oracle">
            <transactionManager type=""></transactionManager>
            <dataSource type=""></dataSource>
        </environment>
    </environments>
    <!--在全局配置文件中引入mapper.xml的配置文件-->
    <!--不带参数-->
    <mappers>
        <mapper resource="UserMapper.xml"></mapper>
    </mappers>
</configuration>
3.3、编写UserMapper.xml配置文件
<?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:命名空间  这个命名空间和其他的命名空间不能重复  一般情况下 实体Mapper
    逻辑上是可以随便写的  但是实际上要见名之意
-->
<mapper namespace="UserMapper">
    <!--insert:标签:表示的是 添加数据到数据库
        id:表示的是方法的名字
        备注:标签之间 就是写SQL语句的地方
    -->
    <!--添加数据-->
    <insert id="insert">
        insert into t_user (username,password) values ('李四','12344');
    </insert>
    <!--修改数据-->
    <update id="update">
        update  t_user set username='王五'
    </update>
    <!--查询数据-->
    <!--resultType:表示返回数据的数据类型-->
    <select id="select" resultType="com.szq.User">
        select * from t_user where id=1
    </select>
    <!--删除数据-->
    <delete id="delete">
        delete from t_user where username='王五'
    </delete>

</mapper>
3.3、编写测试代码(CRUD)
package com.szq;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.Reader;
public class Test001 {
    /**
     * 测试程序
     */
    @Test
    public void testA() throws IOException {
        //1.找到mybatis.xml配置文件
        Reader resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
        //2.创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsReader);
        //通过工厂构建sqlSession对象
        //sqlSession这个对象就是用来操作 数据库的对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //接下来就可以操作数据库了
        //添加数据
//        sqlSession.insert("UserMapper.insert");
        //修改数据
//        sqlSession.update("UserMapper.update");
        //查询数据
//       User o = sqlSession.selectOne("UserMapper.select");
//        System.out.println(o);
        //删除数据
        sqlSession.delete("UserMapper.delete");
        sqlSession.commit();//提交
        sqlSession.close();//关闭
    }
}
4、iBatis的基本的工具类的使用
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 java.io.Reader;

/**
 * 帮助类
 * mybatis帮助类
 */
public class MyBatisUtils {
    //这个类是可以成为成员变量的(没有成员变量,不存在线程安全问题)
    private SqlSessionFactory sqlSessionFactory=null;
    //保存一个线程局部变量
    private ThreadLocal<SqlSession> threadLocal;
   {
       try {
           //需要加载资源
           threadLocal = new ThreadLocal();
           Reader resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
           sqlSessionFactory=new SqlSessionFactoryBuilder().build(resourceAsReader);
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
    /**
     * 获取操作数据库的对象
     *
     */
    public SqlSession getSqlSession(){
        /**
         * 编写访问数据库
         *    1:在一个方法体里面  你调用任何多次数据库  我们只是要求 打开一次数据库 以及关闭一次就可以了
         *    2;简单的说连接是可以重用的
         */
        SqlSession sqlSession = threadLocal.get();
        if(null!=sqlSession){//说明不是第一次访问数据库
            return sqlSession;
        }
        //是第一次访问数据库
        sqlSession = sqlSessionFactory.openSession();
        //方法线程中去
        threadLocal.set(sqlSession);
        return sqlSession;
    }
    /**
     * 关闭
     */
    public void close(){
        SqlSession sqlSession = threadLocal.get();
        if(null!=sqlSession){
            sqlSession.commit();
            sqlSession.close();
            //将线程中的局部变量置空
            threadLocal.remove();
        }
    }
}
5、IBatis的简单使用(二)(IBatis的数据传参的问题)
5.1、传递简单参数问题
5.1.1、编写mybatis.xml配置文件
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--这个文件的作用:是对mybatis的全局配置-->
<configuration>
    <!--
        environments:环境+s,说明可以配置等多个环境
        这里配置的环境是:数据库的连接信息
        default:如果配置了多个环境 默认使用哪一个环境
    -->
    <environments default="mysql">
        <!--配置一个环境:id:表示的是这个环境的名字
            逻辑意义上是可以随便写的
        -->
        <environment id="mysql">
            <!--配置的是事务的类型 ,默认配置JDBC就可以了  一般情况下使用的就是这个类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--这个配置的是数据源  这里你可以认为是固定写法-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
        <!--这里是可以配置多个环境的  要使用哪一个环境那么就就配置上面的default就可以了 -->
        <environment id="oracle">
            <transactionManager type=""></transactionManager>
            <dataSource type=""></dataSource>
        </environment>
    </environments>
    <!--在全局配置文件中引入mapper.xml的配置文件-->
    <!--带参数-->
    <mappers>
        <mapper resource="UserMapper1.xml"></mapper>
    </mappers>
</configuration>
5.1.2、编写UserMapper1.xml配置文件
<?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:命名空间  这个命名空间和其他的命名空间不能重复  一般情况下 实体Mapper
    逻辑上是可以随便写的  但是实际上要见名之意
-->
<mapper namespace="UserMapper">
    <!--传递简单参数  通过id更新数据
         parameterType:表示的是传进去的参数的数据类型
         这个数据类型有两种写法
            1:写Java中数据类型的全路径   java.lang.String   java.lang.Integer
            2:使用mybatis中的数据类型  这个数据类型与 java中的数据类型是一一对应的
         之前的占位符?在这里写成:#{写对应的key的名字}
         简单的数据类型  一个字符串   一个int  一个float  没有key  那么这个时候 这个key
         可以随便写 但是为了见名之意   一般写成value
     -->
    <insert id="insert" parameterType="map">
        insert into t_user(username,password) values (#{username},#{password});
    </insert>
    <update id="update" parameterType="string">
         update  t_user set username='王五' where username=#{username};
    </update>
    <select id="select" parameterType="int" resultType="com.szq.User">
        select * from t_user where id=#{value};
    </select>
    <delete id="delete" parameterType="int">
        delete from t_user where id=#{id}
    </delete>

</mapper>
5.1.3、编写测试代码(CRUD)
package com.szq.parameter;

import com.szq.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.HashMap;

public class Test002 {
    /**
     * 测试带参数
     */
    @Test
    public void testUpdate(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        sqlSession.update("UserMapper.update","张三");
        myBatisUtils.close();
    }
    @Test
    public void testSelect(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        Object o = sqlSession.selectOne("UserMapper.select", 2);
        System.out.println(o);
        myBatisUtils.close();
    }
    @Test
    public void testDelete(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        sqlSession.delete("UserMapper.delete",2);
        myBatisUtils.close();
    }
}
5.2、传递map集合
5.2.1 、编写xml配置文件
<insert id="insert" parameterType="map">
        insert into t_user(username,password) values (#{username},#{password});
    </insert>
5.2.2、编写测试代码
   @Test
    public void testInsert(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("username","张三");
        objectObjectHashMap.put("password","2222");
        sqlSession.insert("UserMapper.insert",objectObjectHashMap);
        myBatisUtils.close();
    }
5.3 、传递数组
5.3.1 、编写xml配置文件
<!--传递数组-->
    <!--动态sql传递数组的问题
        通过一连串的id 找用户对象
         select * from t_user where id in (6,7,8)
         <if>标签用来做条件判断
         如果前端传递的是数组类型的数据  那么 这里使用  list来接收
         遍历数据的时候 那么还是使用 array来做遍历
         collection:表示的是要遍历的这个集合或者数组
         open:sql语句的构成 以什么开始
         close:SQL语句的构成以什么结束
         separator:遍历出来的数据之间使用什么进行分割
         item:每一次遍历出来的数据的名字
         注意:每一次遍历出来的数据 要使用  #{遍历的名字} 去进行获取
    -->
    <select id="findUserById" resultType="com.szq.User" parameterType="list">
        select * from t_user
        <if test="array!=null">
            where id in
            <foreach collection="array" open="(" close=")" separator="," item="id">
                #{id}
            </foreach>
        </if>
    </select>
5.3.2、编写测试代码
    /**
     * 传递数组
     */
    @Test
    public void testFindUserById(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        int arr[]={4,5,6};
        List<User> users = sqlSession.selectList("UserMapper.findUserById", arr);
        System.out.println(users);
        myBatisUtils.close();
    }
5.4、传递集合
5.4.1、编写xml配置文件
 <!--传递集合-->
    <select id="findUserById2" resultType="com.szq.User" parameterType="list">
        select * from t_user
        <if test="list !=null">
            where id
            <foreach collection="list" open="in (" close=")" separator="," item="id">
                #{id}
            </foreach>
        </if>
    </select>
5.4.2、 编写测试代码
  /**
     * 传递集合
     */
    @Test
    public void testFindUserById2(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        ArrayList<Object> objects = new ArrayList<>();
        objects.add(4);
        objects.add(6);
        List<User> users = sqlSession.selectList("UserMapper.findUserById2", objects);
        System.out.println(users);
        myBatisUtils.close();
    }
5.5、传递自定义的类的对象
5.5.1、编写xml文件
 <!--通过用户名和密码找到用户对象
        表示的是传递的是 用户对象
    -->
 <!--传递自定义数据类型User-->
    <select id="select1" parameterType="com.szq.User" resultType="com.szq.User">
        select * from t_user t where  t.username=#{username} and t.password=#{password};
    </select>
5.5.2、编写测试代码
public void testSelect(){
    MyBatisUtils myBatisUtils = new MyBatisUtils();
    SqlSession sqlSession = myBatisUtils.getSqlSession();
//        User user = new User(1,"张三","123");
        User user=new User();
        user.setUsername("张三");
        user.setPassword("123");

        User o = sqlSession.selectOne("UserMapper.select1",user);
    System.out.println(o);
    myBatisUtils.close();
}

说明:不能一次性传递多个简单的参数

因为后端在接受数据的时候 采用的key是随机的 也就说 可以随便写的 假设你传递了多个简单的参数 那么后端无法区分 这个值是哪一个的

没有办法进行传递 ------ 如果要进行传递 那么你就封装成 map集合 或者 java的类

6、动态SQL的问题

什么是动态SQL? 在进行查询的时候 会根据前端传递数据的条件 来动态的进行SQL语句的拼接的这种方法 就称为动态SQL

需求:前端随地的给定一串id 要求的是 这一串的id的用户信息全部查询出来 这一串id可以是任意的

id:1,2,3,4 或者3,2,4,5

select * from t_user where id in(不确定)

动态sql解决的问题

6.1、传递数组
<!--传递数组-->
    <!--动态sql传递数组的问题
        通过一连串的id 找用户对象
         select * from t_user where id in (6,7,8)
         <if>标签用来做条件判断
         如果前端传递的是数组类型的数据  那么 这里使用  list来接收
         遍历数据的时候 那么还是使用 array来做遍历
         collection:表示的是要遍历的这个集合或者数组
         open:sql语句的构成 以什么开始
         close:SQL语句的构成以什么结束
         separator:遍历出来的数据之间使用什么进行分割
         item:每一次遍历出来的数据的名字
         注意:每一次遍历出来的数据 要使用  #{遍历的名字} 去进行获取
    -->
    <select id="findUserById" resultType="com.szq.User" parameterType="list">
        select * from t_user
        <if test="array!=null">
            where id in
            <foreach collection="array" open="(" close=")" separator="," item="id">
                #{id}
            </foreach>
        </if>
    </select>
6.2、传递集合
 <!--传递集合-->
    <select id="findUserById2" resultType="com.szq.User" parameterType="list">
        select * from t_user
        <if test="list !=null">
            where id
            <foreach collection="list" open="in (" close=")" separator="," item="id">
                #{id}
            </foreach>
        </if>
    </select>
6.3、更新数据
<!--插入数据
        prefix:前缀  拼接的前缀
        suffix:拼接的后缀
        suffixOverrides:这个是去掉结束位置的某一个符号  可以是任意的
        prefixOverrides:去掉开始的符号  这个符号是任意的
    -->
    <insert id="insert222" parameterType="com.szq.User">
        insert into t_user
        <trim prefix="(" suffix=")" suffixOverrides="," prefixOverrides="">
            <if test="userName != null">
                userName,
            </if>
            <if test="password !=null">
                password
            </if>
        </trim>

        <trim prefix="values(" suffix=")" suffixOverrides=",">
            <if test="userName != null">
                #{userName},
            </if>
            <if test="password !=null">
                #{password}
            </if>
        </trim>
    </insert>
6.4、动态sql和sql片段
<select id="findUserByCondition" parameterType="com.qf.cd.helloworld.User" resultType="com.qf.cd.helloworld.User">
        select * from t_user where 1=1
        <if test="userName != null">
            and userName=#{userName}
        </if>
        <if test="password !=null">
            and password=#{password}
        </if>
    </select>

    <select id="findUserByCondition1" parameterType="com.szq.User" resultType="com.szq.User">
        select * from t_user
        <include refid="aa"></include>
    </select>

    <!--抽取sql标签
        抽取的sql在任何地方都可以进行调用
    -->
    <sql id="aa">
        <where>
            <if test="userName != null">
                and userName=#{userName}
            </if>
            <if test="password !=null">
                and password=#{password}
            </if>
        </where>
    </sql>
7、iBatis的结果集的返回问题
7.1、返回简单数据
  <!--返回简单参数
        需求:通过用户名 查询用户id
    -->
    <select id="findIdByUserName" parameterType="string" resultType="int">
        select id from t_user where userName=#{value}
    </select>
   @Test
    public void testFindIdByUsername(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        Object id = sqlSession.selectOne("UserMapper.findIdByUserName", "张三");
        System.out.println(id);
        myBatisUtils.close();
    }
7.2、返回自定义的类的对象
 <!--返回简单参数
        需求:通过id   查询用户对象
    -->
    <select id="findUserById" parameterType="int" resultType="com.szq.User">
        select * from t_user where id=#{value}
    </select>
  @Test
    public void testFindUserByUsername(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        Object user = sqlSession.selectOne("UserMapper.findUserById", 6);
        System.out.println(user);
        myBatisUtils.close();
    }
7.3、返回list集合 但是集合中是常见的数据类型
   <!--返回list集合 但是集合中是常见的数据类型-->
<!--    需求:通过一连串的id 查询一连串的名字-->
<!--    如果返回集合的数据类型 那么下面的结果集的返回只用写 集合中泛型的数据类型就OK了-->
    <select id="select2" parameterType="string" resultType="string">
        select username from t_user where id in(4,5,6);
    </select>
  /**
     * 返回list集合 但是集合中是常见的数据类型
     */
    @Test
    public void testFindUserById(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        List<String> str = sqlSession.selectList("UserMapper.select2");
        System.out.println(str);
        myBatisUtils.close();
    }
7.4、返回一个集合 集合中的泛型是自定义的类的类型
 <!--返回一个集合 集合中的泛型是自定义的类的类型-->
    <select id="select3" resultType="com.szq.User">
        select * from t_user ;
    </select>
/**
     * 返回集合,集合是自定义数据类型
     */
    @Test
    public void testFindAllUser(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        List<User> users = sqlSession.selectList("UserMapper.select3");
        System.out.println(users);
        myBatisUtils.close();
    }
8、数据库的字段和实体不对应问题
8.1、解决问题之取别名
 <!--数据库的字段和实体不对应-->
    <!--解决方法1:使用别名-->
    <select id="findUserAll"  resultType="com.szq.parameter1.User">
        	<!--数据库字段  as  实体类字段-->
            select id as userId,username as user_Name,password as pass_Word from t_user;

    </select>
  /**
     * 通过别名的方式
     */
    @Test
    public void testFindUserById(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        List<User> o = sqlSession.selectList("UserMapper.findUserAll");
        System.out.println(o);
        myBatisUtils.close();
    }
8.2、通过结果集映射解决问题
 <!--通过结果集映射解决这个问题-->
    <!--配置结果集映射关系-->
	 <!--type:是结果集返回的类型-->
    <resultMap id="findUserAll2ResultMap" type="com.szq.parameter1.User">
        <!--配置主键映射-->
        <!--property:写实体的字段 column:写数据库的字段-->
        <id property="userId" column="id"></id>
        <!--配置普通字段映射-->
        <result property="user_Name" column="username"></result>
        <result property="pass_Word" column="password"></result>
        <result property="age" column="age"></result>
    </resultMap>
    <select id="findUserAll2"  resultType="com.szq.parameter1.User" resultMap="findUserAll2ResultMap">
        select * from t_user;
    </select>
 /**
     * 配置结果集映射
     */
    @Test
    public void testFindUserById2(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        List<User> o = sqlSession.selectList("UserMapper.findUserAll2");
        System.out.println(o);
        myBatisUtils.close();
    }
9、一对一映射关系

需求:一个用户拥有一个身份证、一个身份证唯一的对应了一个用户

用户与身份证–>是一对一的关系 在查询 用户的时候 ,希望的是能查询出身份证

9.1、用户实体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    //维护
    private IdCard idCard;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class IdCard {
    private int id;
    private String idNum;
    private int userId;
}
9.2 、编写方法的配置
<?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:命名空间  这个命名空间和其他的命名空间不能重复  一般情况下 实体Mapper
    逻辑上是可以随便写的  但是实际上要见名之意
-->
<mapper namespace="UserMapper">
  <!--一对一映射关系-->
  <!--查询到所有的用户以及各自的身份证号码-->
  <!--配置结果集映射-->
  <resultMap id="findUserAllResultMap" type="com.szq.oneToone.User">
    <!--配置主键-->
    <id property="id" column="id"></id>
    <!--配置普通字段的映射-->
    <result property="username" column="username"></result>
    <result property="password" column="password"></result>
    <result property="age" column="age"></result>
    <!--接下来配置一对一的映射关系
            property:这个实际上就是 java实体中 对象关系的名字
            javaType:数据类型(全限定名)
            column:这个是为了将上面的某一个列的内容给映射下来
            相当于 调用方法的时候要传值
            select:相当于要调用另外的mapper来实现整个逻辑
            -->
    <association property="idCard" javaType="com.szq.oneToone.IdCard">
      <!--配置主键映射关系-->
      <id property="id" column="cardid"></id>
      <result property="idNum" column="idNum"></result>
      <result property="userId" column="userId"></result>
    </association>
  </resultMap>
  <select id="findUserAll"  resultMap="findUserAllResultMap">
    select * from t_user t1,t_idcard t2 where t1.id=t2.userId
  </select>
9.3、测试
/**
 * 一对一映射关系
 */
public class Test001 {
    @Test
    public void testOneToOne(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        List<User> o = sqlSession.selectList("UserMapper.findUserAll");
        System.out.println(o);
        myBatisUtils.close();
    }
}
10、一对多映射关系

一个部门有多名员工,在查询部门时需求查出部门下的员工

10.1、部门以及员工实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
    private int id;
    private String deptName;
    private String deptDes;
    private List<Emp> empList;

}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
    private int id;
    private String empName;
    private int gender;
}
10.2、编写xml配置文件
<?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:命名空间  这个命名空间和其他的命名空间不能重复  一般情况下 实体Mapper
    逻辑上是可以随便写的  但是实际上要见名之意
-->
<mapper namespace="DeptMapper">
  <!--一对多映射关系-->
  <!--获取所有的部门,并且要获取一个部门下面的员工-->
  <resultMap id="findDeptResultMap" type="com.szq.oneToMore.Dept">
    <!--主键映射-->
    <id property="id" column="id"></id>
    <!--配置普通字段映射-->
    <result property="deptName" column="deptName"></result>
    <result property="deptDes" column="deptDes"></result>
    <!--一对多-->
    <collection property="empList" ofType="com.szq.oneToMore.Emp">
      <id property="id" column="empid"></id>
      <result property="empName" column="empName"></result>
      <result property="gender" column="gender"></result>
    </collection>
  </resultMap>
  <select id="findDept" resultMap="findDeptResultMap">
    select * from t_dept t1,t_emp t2 where t2.deptid=t1.id;
  </select>
10.3、测试

/**
 * 一对多映射关系
 */
public class Test001 {
    @Test
    public void testOneToMore(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        List<Dept> o = sqlSession.selectList("DeptMapper.findDept");
        System.out.println(o);
        myBatisUtils.close();
    }
}
11、取别名的问题

为什么要整个别名? 因为我们很多时候在写 这个java类型的时候 都写的的全路径

简单的说就是为了解决 传入参数的类型过长 以及 返回参数的类型 过长的问题

mybatis.xml中进行配置

<!--取别名-->
    <typeAliases>
        <!--
            type:是要取别名的这个java类型
            alias:这个是别名的名字
            别名一般情况下是取给java实体类的  po   dto
        -->
       <!-- <typeAlias type="com.szq.one2many.Dept" alias="deptbobo"></typeAlias>
        <typeAlias type="com.szq.one2many.Employee" alias="empbobo"></typeAlias>-->

        <!--这个就表示的是给这个包里所有的类都取别名
            默认的别名的名字是 类名的首写字母小写
        -->
        <package name="com.szq.one2many"></package>
    </typeAliases>
12、懒加载的问题
12.1、关闭积极的加载、开启懒加载
<!--iBatis本身的设置 -->
<!--mybatis.xml里面设置:注意放置顺序-->
    <settings>
        <!--是否使能延迟的加载 -->
        <setting name="lazyLoadingEnabled" value="true" />
        <!--关闭那个积极的加载 -->
        <setting name="aggressiveLazyLoading" value="false" />
    </settings>
12.2、xml配置问题
<!--mybatis.xml里面的mappers配置如下-->
   <mappers>
       <mapper resource="UserMapper4.xml"></mapper>
        <!--懒加载配置如下-->
       <mapper resource="IdCardMapper.xml"></mapper>
    </mappers>
<?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:命名空间  这个命名空间和其他的命名空间不能重复  一般情况下 实体Mapper
    逻辑上是可以随便写的  但是实际上要见名之意
-->
<mapper namespace="UserMapper">
  <!--一对一映射关系-->
  <!--查询到所有的用户以及各自的身份证号码-->
  <!--配置结果集映射-->
  <resultMap id="findUserAllResultMap" type="com.szq.oneToone.User">
    <!--配置主键-->
    <id property="id" column="id"></id>
    <!--配置普通字段的映射-->
    <result property="username" column="username"></result>
    <result property="password" column="password"></result>
    <result property="age" column="age"></result>
    <!--接下来配置一对一的映射关系
            property:这个实际上就是 java实体中 对象关系的名字
            javaType:数据类型(全限定名)
            column:这个是为了将上面的某一个列的内容给映射下来
            相当于 调用方法的时候要传值
            select:相当于要调用另外的mapper来实现整个逻辑
            -->
    <!--懒加载-->
    <association property="idCard" column="id" javaType="com.szq.oneToone.IdCard" select="IdCardMapper.findIdCard" fetchType="lazy">

    </association>
  </resultMap>
  <select id="findUserAll"  resultMap="findUserAllResultMap">
    select * from t_user  where id=4;
  </select>
</mapper>
12.3、测试代码
/**
 * 测试懒加载
 */
public class Test002 {
    @Test
    public void test(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        List<Object> objects = sqlSession.selectList("UserMapper.findUserAll");
//        System.out.println(objects);
        myBatisUtils.close();

    }
}
13、二级缓存的问题

缓存:简单的说就是将查询出来的数据 放到一个地方,下一次查询相同的数据的时候不用去查询数据库

直接从缓存里面取数据,这样能够减轻SQL数据库的压力。

13.1、一级缓存

一级缓存又叫做session缓存。整个缓存的生命周期由session来进行管理 ,session死了,那么缓存也没有了。

也就是说 一级缓存 实际上存在的范围是 sqlsession的创建完成到sqlsession的关闭之前。

    @Test
    public void test1(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        User users=sqlSession.selectOne("UserMapper.findUserAll");
        
        User users1=sqlSession.selectOne("UserMapper.findUserAll");

        User users3=sqlSession.selectOne("UserMapper.findUserAll");

        User users4=sqlSession.selectOne("UserMapper.findUserAll");

        User users5=sqlSession.selectOne("UserMapper.findUserAll");

        User users6=sqlSession.selectOne("UserMapper.findUserAll");

        User users7=sqlSession.selectOne("UserMapper.findUserAll");
        //清空一级缓存
        sqlSession.clearCache();
        sqlSession.commit();
        sqlSession.close();
    }

查询相同的数据,也就是说sql语句相同,在sqlsession的创建完成到sqlsession的关闭之前,相同的sql语句只会执行一次----一级缓存。一级缓存是不能跨session的 ,现实开发中并没有什么用 ,而且这个缓存的维护 ,也并不需要我们人为的去完成,缓存的使能和销毁都是由session自身去完成的

13.2、二级缓存

二级缓存解决了一级缓存的缺点,它能够session进行使用 ,在开发中 一般我们使用的都是二级缓存。

开启二级缓存

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

导入mybatis的ehcache的支持包

github上下载:https://github.com/mybatis/ehcache-cache/releases

在这里插入图片描述

在这里插入图片描述

在resource目录下配置ehcache.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache
        updateCheck="false">
    <!-- 缓存写入文件目录    不需要你引入的  只是配置好就可以  他会默认来找当前的这个位置-->
    <diskStore path="d:\\mytemp"/>
    <!-- 数据过期策略 -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
    />
</ehcache>

在需要缓存内容的mapper上 使用cache标签

<!--二级缓存的地方-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
 * 测试二级缓存
 */
@Test
public void test2(){
    MyBatisUtils myBatisUtils = new MyBatisUtils();
    SqlSession sqlSession = myBatisUtils.getSqlSession();
    List<Object> objects1 = sqlSession.selectList("UserMapper.findUserAll");
    myBatisUtils.close();
    MyBatisUtils myBatisUtils1 = new MyBatisUtils();
    SqlSession sqlSession1= myBatisUtils1.getSqlSession();
    List<Object> objects2 = sqlSession1.selectList("UserMapper.findUserAll");
    myBatisUtils1.close();
    MyBatisUtils myBatisUtils2 = new MyBatisUtils();
    SqlSession sqlSession2 = myBatisUtils2.getSqlSession();
    List<Object> objects3 = sqlSession2.selectList("UserMapper.findUserAll");
    myBatisUtils2.close();
}

**测试结果**

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200625204852339.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzA4NDg1Nw==,size_16,color_FFFFFF,t_70#pic_center)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果在iBatis使用iterate进行批量插入处理,而且表名不确定,需要通过参数传递进SQL语句中,可以使用动态SQL语句和参数映射来实现。 具体步骤如下: 1. 在iBatis的SQL语句中,使用动态SQL语句来拼接表名。可以使用if标签判断表名是否为空,如果为空,则使用默认表名;如果不为空,则拼接传递进来的表名。 ``` <insert id="batchInsert"> INSERT INTO <if test="tableName != null and tableName != ''"> ${tableName} </if> <if test="tableName == null or tableName == ''"> default_table_name </if> (column1, column2, column3) VALUES <iterate property="list" open="(" close=")" conjunction=","> #{item.column1},#{item.column2},#{item.column3} </iterate> </insert> ``` 2. 在iBatis的SqlMapClientTemplate中,将表名作为参数传递进insert方法中,并将参数映射到SQL语句中。 ``` public void batchInsert(String tableName, List<Entity> list) { Map<String, Object> paramMap = new HashMap<>(); paramMap.put("tableName", tableName); paramMap.put("list", list); sqlSessionTemplate.insert("batchInsert", paramMap); } ``` 在这个示例代码中,tableName是需要动态拼接的表名,list是需要插入的数据列表。在batchInsert方法中,将tableName和list封装成Map类型的参数,然后将参数传递进insert方法中,最终参数会被映射到SQL语句中,实现动态拼接表名的功能。 注意,在动态拼接表名时,需要使用${}来引用表名变量,而不是#{}。因为#{}会将表名参数作为字符串进行转义,而${}则不会进行转义,所以可以正确拼接表名。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值