Mybatis系列(四)XML 映射器

Mybatis系列(四)XML 映射器

前言

MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。

一、SQL映射文件的标签分类

SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):

  • cache – 该命名空间的缓存配置。
  • cache-ref – 引用其它命名空间的缓存配置。
  • resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
  • parameterMap – 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。
  • sql – 可被其它语句引用的可重用语句块。
  • insert – 映射插入语句。
  • update – 映射更新语句。
  • delete – 映射删除语句。
  • select – 映射查询语句。

1.1、Select

首先介绍select标签中可以设置的所有属性,见下图:

在这里插入图片描述

各个值的解释见下图:

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和 parameterType 属性。
resultType期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
resultMap对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。
flushCache将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。
useCache将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
fetchSize这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetTypeFORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。
databaseId如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。
resultOrdered这个设置仅针对嵌套结果 select 语句:如果为 true,将会假设包含了嵌套结果集或是分组,当返回一个主结果行时,就不会产生对前面结果集的引用。 这就使得在获取嵌套结果集的时候不至于内存不够用。默认值:false
resultSets这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。

1.2、Insert/Update/Delete

首先介绍一下update和insert标签支持的属性,见下图:

在这里插入图片描述

其次,对于各个属性的理解,请见下表:

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和 parameterType 属性。
flushCache将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
useGeneratedKeys(仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
keyProperty(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
keyColumn(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。
databaseId如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。
  1. useGeneratedKeyskeyProperty等两个属性举个例子

使用场景:

对于支持主键自增的某些数据库而言(比如Mysql),我们增加一条数据之后,后面的业务可能会涉及到刚刚生成的主键的使用,因此我们需要拿到这个生成好的主键。

SQL映射文件:

<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO
            t_employee(empName , email , gender)
        VALUES (#{empName} , #{email} , #{gender})
    </insert>

测试代码:

@Test
    public void testMybatisInsert(){
        //获取与数据库的一次会话
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        try {
            EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);
            Employee employee = new Employee(null, "lisi", "lisi@qq.com", 2);
            int i = employeeDao.insertEmployee(employee);
            System.out.println("成功增加了"+i+"条");
            System.out.println("数据库生成的id为:"+employee.getId());
        }finally {
            sqlSession.close();
        }
    }

输出结果:

成功增加了1条
数据库生成的id为:10
  1. SelectKey的使用

使用场景:

对于不支持自动生成主键列的数据库和可能不支持自动生成主键的 JDBC 驱动,MyBatis 有另外一种方法来生成主键,也就是selectKey,请看下面的具体事例来了解selectKey的使用

selectKey的属性介绍:

属性描述
keyPropertyselectKey 语句结果应该被设置到的目标属性。如果生成列不止一个,可以用逗号分隔多个属性名称。
keyColumn返回结果集中生成列属性的列名。如果生成列不止一个,可以用逗号分隔多个属性名称。
resultType结果的类型。通常 MyBatis 可以推断出来,但是为了更加准确,写上也不会有什么问题。MyBatis 允许将任何简单类型用作主键的类型,包括字符串。如果生成列不止一个,则可以使用包含期望属性的 Object 或 Map。
order可以设置为 BEFOREAFTER。如果设置为 BEFORE,那么它首先会生成主键,设置 keyProperty 再执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 中的语句 - 这和 Oracle 数据库的行为相似,在插入语句内部可能有嵌入索引调用。
statementType和前面一样,MyBatis 支持 STATEMENTPREPAREDCALLABLE 类型的映射语句,分别代表 Statement, PreparedStatementCallableStatement 类型。

测试示例:

SQL映射文件:

<!--测试selectKey的使用,此次测试之前,先选取一个不能自动生成主键的数据库,比如Oracle-->
    <insert id="insertEmployee2">
        <selectKey  keyProperty="id" order="BEFORE" statementType="PREPARED" resultType="integer">
            select max(id)+1 from t_employee
        </selectKey>
        <!--在sql语句执行之前,先给主键生成一个值-->
        INSERT INTO
            t_employee(id , empName , email , gender)
        VALUES (#{id} , #{empName} , #{email} , #{gender})
    </insert>

Test.java:

@Test
    public void testMybatisInsert2(){
        //获取与数据库的一次会话
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        try {
            EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);
            Employee employee = new Employee(null, "lisi", "lisi@qq.com", 2);
            int i = employeeDao.insertEmployee2(employee);
            System.out.println("成功增加了"+i+"条");
            System.out.println("生成的id为:"+employee.getId());
        }finally {
            sqlSession.close();
        }
    }

输出结果:

成功增加了1条
生成的id为:6

二、参数

场景:

我们在进行CRUD的时候,不同的方法可能传入一个或者多个不同类型的参数,在SQL映射文件我们要将每个方法的每一个参数都取出来进行赋值,然后进行SQL语句的查询

参数分类:

  1. 单个参数

    (1) 基本类型的参数

    如public Employee getEmployee(int id)

    (2) pojo

    如public int saveEmployee(Employee employee)

  2. 多个参数(可提供命名参数,@Param)

    如public int getEmployee(int id , String empName)

  3. map参数

    如public int getEmployee(Map<String , Object> paramMap)

    另外,JDBC 要求,如果一个列允许使用 null 值,并且会使用值为 null的参数,就必须要指定 JDBC 类型

测试用例:

  1. 针对于单个参数的两种情况,见以下例子:

SQL映射文件:

	<!--基本类型的参数,此种情况下直接取出来的就是当前方法参数位置的值-->
	<select id="getEmployeeByID" resultType="employee">
        select * from t_employee where id = #{id}
    </select>
	<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO
            t_employee(empName , email , gender)
        VALUES (#{empName} , #{email , jdbcType = VARCHAR} , #{gender})
    </insert>

EmployeeDao.java

Employee getEmployeeByID(Integer id);

int insertEmployee(Employee employee);
  1. 针对于多个参数的两种情况,见以下例子:

SQL映射文件:

<select id="getEmployeeByIdAndEmpName" resultType="employee">
        select * from t_employee where id = #{id} and empName = #{empName}
</select>

EmployeeDao.java:

//对于多个参数而言,提供命名参数
Employee getEmployeeByIdAndEmpName(@Param("id") int id,
                                   @Param("empName") String empName);
  1. map参数

SQL映射文件:

<select id="getEmployeeByParamMap" resultType="employee">
        select * from t_employee where id = #{id} and empName = #{empName}
</select>

EmployeeDao.java:

Employee getEmployeeByParamMap(Map<String, Object> paramMap);

Test.java:

 @Test
    public void testMybatisSelect2(){
        //获取与数据库的一次会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);
            Map<String , Object> paramMap = new HashMap<>();
            paramMap.put("id" , "2");
            paramMap.put("empName" , "lisi");
            Employee employee = employeeDao.getEmployeeByParamMap(paramMap);
            System.out.println("查询到的员工为:" + employee);
        }finally {
            sqlSession.close();
        }
    }
  1. 多个不同类型的参数组合

SQL映射文件:

<select id="getEmployeeByCombinationParams" resultType="employee">
        select * from t_employee
            where
            id = #{paramsMap.id}
            and login_account = #{emp.loginAccount}
            and empName = #{empName}
    </select>

EmployeeDao.java:

Employee getEmployeeByCombinationParams(@Param("paramsMap") Map<String, Object> paramMap,
                                        @Param("emp") Employee emp,
                                        @Param("empName") String empName);

Test.java:

 @Test
    public void testMybatisSelect3(){
        //获取与数据库的一次会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);
            Map<String , Object> paramMap = new HashMap<>();
            paramMap.put("id" , "2");
            Employee emp = new Employee();
            emp.setLoginAccount("admin");
            Employee employee = employeeDao.getEmployeeByCombinationParams(paramMap , emp , "lisi");
            System.out.println("查询到的员工为:" + employee);
        }finally {
            sqlSession.close();
        }
    }

2.1、#{}与${}的区别

  1. #{}是参数预编译方式,参数位置都用?替代,参数都是预编译后设置进去的,比较安全,可以防止SQL注入,因为SQL注入只会在预编译前起作用。
  2. ${}不是参数预编译,而是直接取出值与SQL进行拼串,会出现注入问题。**

数据库中的现有数据:

在这里插入图片描述

SQL映射文件:

<select id="getEmployees" resultType="employee">
        select * from
            ${tableName}
        where id = #{id} and 
    	empName = ${empName}
</select>

接口:

Employee getEmployees(@Param("id") int id,
                      @Param("empName") String empName,
                      @Param("tableName") String tableName);

测试类:

@Test
    public void testMybatisSelect4(){
        //获取与数据库的一次会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);
            //此处也能查询出来数据,会出现注入问题,在可以预编译的位置一定要使用#{}
            Employee employee = employeeDao.getEmployees(2 , "'xxxxxx' or 1=1" , "t_employee");
            System.out.println("查询到的员工为:" + employee);
        }finally {
            sqlSession.close();
        }
    }

测试结果:

DEBUG 02-13 18:53:20,491 ==>  Preparing: select * from t_employee where id = ? and empName = 'xxxxxx' or 1=1   (BaseJdbcLogger.java:145) 
DEBUG 02-13 18:53:20,567 ==> Parameters: 2(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 02-13 18:53:20,601 <==      Total: 1  (BaseJdbcLogger.java:145) 
查询到的员工为:Employee{id=2, empName='lisi', email='lisi@qq.com', gender=2, loginAccount='admin'}

三、查询

3.1、查询返回list

注意resultType必须为对象的全类名或者别名

SQL映射文件:

<select id="getEmps" resultType="employee">
        select * from t_employee
    </select>

接口:

    List<Employee> getEmps();

测试类:

	@Test
    public void testMybatisSelect5(){
        //获取与数据库的一次会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);
            List<Employee> emps = employeeDao.getEmps();
            for (Employee emp : emps) {
                System.out.println("查询到的员工为:" + emp);
            }
        }finally {
            sqlSession.close();
        }
    }

测试结果:

查询到的员工为:Employee{id=2, empName='lisi', email='lisi@qq.com', gender=2, loginAccount='admin'}
查询到的员工为:Employee{id=3, empName='212', email='12', gender=1, loginAccount='null'}

3.2、查询返回map

  1. 返回单个结果集封装成Map

  2. 返回多个结果集封装为Map

    注意resultType必须为`Employee对象的全类名或者别名

    @MapKey("id")指定封装的map的key为id,value为Employee对象

  1. 返回单个结果集封装成Map

xml:

	<select id="getEmpReturnSingleMap" resultType="map">
        select * from t_employee where id = #{id}
    </select>

接口:

Map<String , Object> getEmpReturnSingleMap(Integer id);

测试类:

@Test
    public void testMybatisSelect6(){
        //获取与数据库的一次会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);
            Map<String, Object> map = employeeDao.getEmpReturnSingleMap(2);
            System.out.println(map);
        }finally {
            sqlSession.close();
        }
    }

测试结果:

{gender=2, empName=lisi, id=2, login_account=admin, email=lisi@qq.com}
  1. 返回多个结果集封装为Map

xml:

<select id="getEmpReturnMulMap" resultType="employee">
        select * from t_employee
    </select>

接口:

@MapKey("id")
   Map<Integer , Employee> getEmpReturnMulMap();

测试类:

 @Test
    public void testMybatisSelect7(){
        //获取与数据库的一次会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);
            Map<Integer, Employee> employeeMap = employeeDao.getEmpReturnMulMap();
            System.out.println(employeeMap);
        }finally {
            sqlSession.close();
        }
    }

测试结果:

{2=Employee{id=2, empName='lisi', email='lisi@qq.com', gender=2, loginAccount='admin'}, 3=Employee{id=3, empName='212', email='12', gender=1, loginAccount='null'}, 9=Employee{id=9, empName='null', email='lisi@qq.com', gender=2, loginAccount='null'}}

3.3、resultMap自定义封装规则

使用场景:

对于数据库表的列名与javaBean的属性名不匹配的情况,有以下三种解决方案:

  1. 在mybatis全局配置中开启驼峰命名规则,前提是数据库列名与javaBean属性名必须满足驼峰规则,如c_name与cName
  2. 编写SQL语句时起别名与javaBean的属性名对应
  3. 使用resultMap进行数据库字段名与javaBean属性名一一映射

示例:

cat表:

在这里插入图片描述

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">
<mapper namespace="com.cetc.dao.CatDao">

    <select id="getCatByID" resultMap="myCat">
        select * from t_cat where cid = #{id}
    </select>
    
    <!--
        1. id表示resultMap的标识,type表示返回值的类型
        2.<id/>表示指定表的主键
        3.property表示javaBean属性名,column表示javaBean字段名
    -->
    <resultMap id="myCat" type="com.cetc.bean.Cat">
        <id property="id" column="cid"/>
        <result property="name" column="cname"/>
        <result property="age" column="cage"/>
        <result property="gender" column="cgender"/>
    </resultMap>

</mapper>

接口:

Cat getCatByID(Integer id);

javaBean:

@Data
public class Cat {
    private Integer id;
    private String name;
    private Integer age;
    private Integer gender;
}

测试类:

@Test
    public void testMybatisSelect(){
        //获取与数据库的一次会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            CatDao catDao = sqlSession.getMapper(CatDao.class);
            Cat cat = catDao.getCatByID(1);
            System.out.println(cat);
        }finally {
            sqlSession.close();
        }
    }

测试结果:

Cat(id=1, name=TOM, age=10, gender=0)

3.4、1:1/1:N/N:N关联查询

  1. 一对一查询一对多一般把外键设置在多的那一方,的那一方对于每条记录来说相当于只对应了一条记录
  2. 多对多需要设置中间表

下面,就以锁与钥匙的关系来进行举例说明

一对一示例介绍:

数据库设计如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fkGMNrJx-1613556677082)(C:\Users\86173\Desktop\自我总结\images\mybatis\4.png)]

Key:

@Data
public class Key {
    private Integer id;
    private String keyName;
    //一对一的关系
    private Lock lock;
}

Lock:

@Data
public class Lock {
    private Integer id;
    private String lockName;
}

KeyDao.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">
<mapper namespace="com.cetc.dao.KeyDao">

    <select id="getKeyById" resultMap="myKey">
        SELECT
	        *
        FROM
	    t_key k,
	    t_lock l
        WHERE
	    k.l_id = l.lid
	    AND k.kid = #{id}
    </select>
	
    <!--方式一:使用级联属性-->
    <!--<resultMap id="myKey" type="com.cetc.bean.Key">
        <id property="id" column="kid"/>
        <result property="keyName" column="kname"/>
        <result property="lock.id" column="lid"/>
        <result property="lock.lockName" column="lname"/>
    </resultMap>-->
    <!--方式二:使用association进行描述对象的属性-->
    <resultMap id="myKey" type="com.cetc.bean.Key">
        <id property="id" column="kid"/>
        <result property="keyName" column="kname"/>
        <!--
			1.property:属性名称
			2.javaType:Key中对应Lock的类型全类名或者别名
		-->
        <association property="lock" javaType="com.cetc.bean.Lock">
            <id property="id" column="lid"/>
            <result property="lockName" column="lname"/>
        </association>
    </resultMap>
</mapper>

测试方法:

@Test
    public void testMybatisSelect(){
        //获取与数据库的一次会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            KeyDao keyDao = sqlSession.getMapper(KeyDao.class);
            Key key = keyDao.getKeyById(1);
            System.out.println(key);
        }finally {
            sqlSession.close();
        }
    }

测试结果:

Key(id=1, keyName=钥匙1, lock=Lock(id=1, lockName=1))

一对多示例介绍:

Lock:

@Data
public class Lock {
    private Integer id;
    private String lockName;
    private List<Key> keyList;
}

Key:

@Data
public class Key {
    private Integer id;
    private String keyName;
    private Lock lock;
}

lockDao:

<?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">
<mapper namespace="com.cetc.dao.LockDao">
    <select id="getLockById" resultMap="mylock">
       SELECT
	    l.* , k.kid , k.kname , k.l_id as l
        FROM
	    t_lock l
	    INNER JOIN t_key k ON l.lid = k.l_id
	    AND l.lid = #{id}
    </select>
    <!--一对多关系-->
    <resultMap id="mylock" type="com.cetc.bean.Lock">
        <id column="lid" property="id"/>
        <result column="lockName" property="lockName"/>
        <!--用于关联集合
			1.property表示javaBean属性名称
			2.ofType表示集合的泛型名称,即Key的全类名或者别名
		-->
        <collection property="keyList" ofType="com.cetc.bean.Key">
            <id property="id" column="kid"/>
            <result property="keyName" column="kname"/>
        </collection>
    </resultMap>
</mapper>

对于业务比较复杂的情况,写的连接查询比较多的情况下,mybatis提供了按需加载的策略,具体的配置方法如下:

设置名描述
lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。true | falsefalse
aggressiveLazyLoading开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载,可通过fetchType来进行覆盖true | falsefalse (在 3.4.1 及之前的版本中默认为 true)

全局配置:

<settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
</settings>

KeyDao.xml:

<select id="getKeyBySimple" resultMap="myKeySimple">
        select kid , kname , l_id  from t_key where kid = #{id}
</select>

<resultMap id="myKeySimple" type="com.cetc.bean.Key">
        <id property="id" column="kid"/>
        <result property="keyName" column="kname"/>
        <association property="lock" select="com.cetc.dao.LockDao.getLockBySimple" column="l_id"  />
</resultMap>

LockDao.xml

 <select id="getLockBySimple" resultMap="lockResultMap">
        select * from t_lock where lid = #{id}
    </select>
    <resultMap id="lockResultMap" type="com.cetc.bean.Lock">
        <id column="lid" property="id"/>
        <result column="lname" property="lockName"/>
    </resultMap>

测试类:

@Test
    public void testMybatisSelect02(){
        //获取与数据库的一次会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            KeyDao keyDao = sqlSession.getMapper(KeyDao.class);
            Key key = keyDao.getKeyBySimple(1);
        
            System.out.println(key.getKeyName());

            Thread.sleep(3000);

            System.out.println(key.getLock().getLockName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

测试结果:

DEBUG 02-16 00:23:17,333 ==>  Preparing: select kid , kname , l_id from t_key where kid = ?   (BaseJdbcLogger.java:145) 
DEBUG 02-16 00:23:17,556 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 02-16 00:23:18,076 <==      Total: 1  (BaseJdbcLogger.java:145) 
钥匙1
DEBUG 02-16 00:23:21,079 ==>  Preparing: select * from t_lock where lid = ?   (BaseJdbcLogger.java:145) 
DEBUG 02-16 00:23:21,081 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 02-16 00:23:21,085 <==      Total: 1  (BaseJdbcLogger.java:145)1

y.getKeyName());

        Thread.sleep(3000);

        System.out.println(key.getLock().getLockName());
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        sqlSession.close();
    }
}

`测试结果:`

```java
DEBUG 02-16 00:23:17,333 ==>  Preparing: select kid , kname , l_id from t_key where kid = ?   (BaseJdbcLogger.java:145) 
DEBUG 02-16 00:23:17,556 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 02-16 00:23:18,076 <==      Total: 1  (BaseJdbcLogger.java:145) 
钥匙1
DEBUG 02-16 00:23:21,079 ==>  Preparing: select * from t_lock where lid = ?   (BaseJdbcLogger.java:145) 
DEBUG 02-16 00:23:21,081 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 02-16 00:23:21,085 <==      Total: 1  (BaseJdbcLogger.java:145) 
锁1

与collection与associate用法一致

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值