Data Access 之 MyBatis(三) - SQL Mapping XML(Part C)(上)

简介: Data Access 之 MyBatis(三) - SQL Mapping XML(Part C)

一、联合查询

resultMap自定义封装规则

当实体类属性和数据库字段的差异仅仅是 "_" 时,可以通过驼峰转换或者SQL语句中起别名的方式,如果属性和字段不一致,驼峰命名法就无法使用了,而起别名的方式较为繁琐,这时候就可以使用resultMap自定义封装规则

创建一张表t_cat

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_cat
-- ----------------------------
DROP TABLE IF EXISTS `t_cat`;
CREATE TABLE `t_cat` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `cName` varchar(255) DEFAULT NULL,
  `cAge` int(2) DEFAULT NULL,
  `cgender` int(1) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_cat
-- ----------------------------
BEGIN;
INSERT INTO `t_cat` VALUES (1, '皮皮', 2, 0);
INSERT INTO `t_cat` VALUES (2, '六六', 1, 0);
INSERT INTO `t_cat` VALUES (3, '猪', 1, 0);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
复制代码

entity包中增加实体类Cat

@Data
public class Cat {
    private Integer id;
    private String name;
    private Integer gender;
    private Integer age;
}
复制代码

dai包中增加CatDao接口

public interface CatDao {
    Cat getCatById(Integer id);
}
复制代码

mappers目录下增加SQL映射文件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.citi.dao.CatDao">
    <!--参数类型不用写-->
    <select id="getCatById" resultType="com.citi.entity.Cat">
        select * from t_cat where id = #{id}
    </select>
</mapper>
复制代码

将cat.xml注册到MyBatis全局配置文件中

<mappers>
    <mapper resource="mappers/employee.xml"/>
    <mapper resource="mappers/cat.xml"/>
</mappers>
复制代码

生成CatDaoTest测试类

public class CatDaoTest {
    SqlSessionFactory sqlSessionFactory = null;
    SqlSession openSession = null;
    @Before
    public void setUp() throws Exception {
        //1、根据全局配置文件创建出一个SqlSessionFactory
        //SqlSessionFactory:是SqlSession工厂,负责创建SqlSession对象;
        //SqlSession:sql会话(代表和数据库的一次会话);
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        openSession = sqlSessionFactory.openSession();
    }
    @Test
    public void getCatById() {
        CatDao catDao = openSession.getMapper(CatDao.class);
        Cat cat = catDao.getCatById(1);
        System.out.println(cat);
    }
}
复制代码

执行测试方法

c4403ce5758f4ffa95bc5c3fb44c8bb1_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

除了ID,其余属性都是null,MyBatis默认可以自动封装结果集,但前提是数据库字段和属性值一一对应(不区分大小写),出现这种情况的原因是数据库的字段和实体类属性不一致,导致对象的部分属性赋值失败。如果数据库字段和实体类属性名字的区别只是有无下划线,那么可以在MyBatis全局配置文件中开启驼峰命名法来解决。如果完全不一致则有两种解决办法。

第一种解决办法是在查询SQL中给查询的字段起别名,使之与实体类属性名一致。修改映射文件

<select id="getCatById" resultType="com.citi.entity.Cat">
    select id, cname name, cage age, cgender gender from t_cat where id = #{id}
</select>
复制代码

再次执行测试

65a3d61e815f4b99a26e7ce6ccf398d4_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

第二种方法是使用resultMap标签自定义结果集,实现数据库字段和实体类属性的对应,resultType和resultMap是互斥的,使用了resultMap就不要再使用resultType

<select id="getCatById" resultMap="mycat">
    select * from t_cat where id = #{id}
</select>
<resultMap id="mycat" type="com.citi.entity.Cat">
    <!--定义主键映射规则-->
    <id property="id" column="id"></id>
    <!--普通列的映射规则-->
    <result property="gender" column="cgender"></result>
    <result property="age" column="cage"></result>
    <result property="name" column="cname"></result>
</resultMap>
复制代码
  • type:指定为哪一个实体类自定义封装规则,全类名
  • id:唯一标识,被其他引用
  • column:指定的数据库的字段
  • property:指的是实体类的属性
  • result:标签用来定义非主键列的映射规则

执行测试

e3e0966ed3aa41d19993e8ab26900f76_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

联合查询

由于实体类和数据库表是一一对应的,当进行联合查询时没有哪一个实体类可以与联合查询的结果一一对应,这时就可以使用resultMap来封装联合查询的结果

一对一查询

在entity包中新增两个实体类Key、Lock,两者为一对一关系

@Data
public class Key {
    private Integer id;
    private String keyName;
    // 能打开的锁
    private Lock lock;
}
复制代码
@Data
public class Lock {
    private Integer id;
    private String lockName;
}
复制代码

创建数据库表,并通过外键建立关联关系,并插入两条数据

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_key
-- ----------------------------
DROP TABLE IF EXISTS `t_key`;
CREATE TABLE `t_key` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `keyname` varchar(255) DEFAULT NULL,
  `lockid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_key_lock` (`lockid`),
  CONSTRAINT `fk_key_lock` FOREIGN KEY (`lockid`) REFERENCES `t_lock` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for t_lock
-- ----------------------------
DROP TABLE IF EXISTS `t_lock`;
CREATE TABLE `t_lock` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `lockName` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
复制代码

在dao包中新建KeyDao接口

public interface KeyDao {
    Key getKeyById(Integer id);
}
复制代码

在mappers中新增key.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.citi.dao.KeyDao">
    <!--参数类型不用写-->
    <select id="getKeyById" resultMap="mykey">
        SELECT k.id,k.keyname,k.lockid, l.id lid, l.lockname
        FROM t_key k
        LEFT JOIN t_lock l ON k.lockid = l.id
        WHERE k.id = #{id}
    </select>
    <resultMap id="mykey" type="com.citi.entity.Key">
        <id property="id" column="id"></id>
        <result property="keyName" column="keyname"></result>
        <result property="lock.id" column="lid"></result>
        <result property="lock.lockName" column="lockName"></result>
    </resultMap>
</mapper>
复制代码

SQL查询语句建议使用left Join,不易错。多表联合查询一定要使用resultMap,自定封装规则。这里使用级联属性获取key中所包含的lock的属性

在全局配置文件中注册key.xml

<mappers>
    <mapper resource="mappers/employee.xml"/>
    <mapper resource="mappers/cat.xml"/>
    <mapper resource="mappers/key.xml"/>
</mappers>
复制代码

增加测试类KeyDaoTest

public class KeyDaoTest {
    SqlSessionFactory sqlSessionFactory = null;
    SqlSession openSession = null;
    @Before
    public void setUp() throws Exception {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        openSession = sqlSessionFactory.openSession();
    }
    @Test
    public void getKeyById() {
        KeyDao keyDao = openSession.getMapper(KeyDao.class);
        Key key = keyDao.getKeyById(1);
        System.out.println(key);
    }
}
复制代码

执行测试

81b4f632c6334ad7a4f5a2568e21649d_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

上述方式使用到了级联属性,而MyBatis推荐使用association属性来完成自定义封装规则

修改resultMap

<resultMap id="mykey" type="com.citi.entity.Key">
    <id property="id" column="id"></id>
    <result property="keyName" column="keyname"></result>
    <!--<result property="lock.id" column="lid"></result>-->
    <!--<result property="lock.lockName" column="lockName"></result>-->
    <association property="lock" javaType="com.citi.entity.Lock">
        <id property="id" column="id"></id>
        <result property="lockName" column="lockName"></result>
    </association>
</resultMap>
复制代码
  • association:定义一个复杂类型的关联
  • javaType:指定对象的类型

再次执行测试

19ac7a48b6ef45a78bd696297d8b9e9e_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

一对多查询

在数据库表中新增数据一个3号锁,有多把钥匙可以打开3号锁,也就是说一把锁有多把钥匙,这就形成了一对多的关系

修改Lock实体类,增加钥匙列表的属性

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

一对一和一对多的区别在于所站的角度不同,一对多是外键建立在多的一方,多对多时通过中间表建立关系

在dao包中新建LockDao

public interface LockDao {
    Lock getLockById(Integer id);
}



相关文章
|
1月前
|
XML Java 数据库连接
mybatis中在xml文件中通用查询结果列如何使用
mybatis中在xml文件中通用查询结果列如何使用
37 0
|
5月前
|
XML Java 数据库连接
手写mybatis xml版本
手写mybatis xml版本
30 0
|
5月前
|
SQL Java 数据库连接
MyBatis【源码探究 01】mapper.xml文件内<if test>标签判断参数值不等于null和空(当参数值为0)时筛选条件失效原因分析
MyBatis【源码探究 01】mapper.xml文件内<if test>标签判断参数值不等于null和空(当参数值为0)时筛选条件失效原因分析
112 0
MyBatis【源码探究 01】mapper.xml文件内<if test>标签判断参数值不等于null和空(当参数值为0)时筛选条件失效原因分析
|
1天前
|
XML Java 数据库连接
Mybatis逆向工程的2种方法,一键高效快速生成Pojo、Mapper、XML,摆脱大量重复开发
Mybatis逆向工程的2种方法,一键高效快速生成Pojo、Mapper、XML,摆脱大量重复开发
14 6
|
5天前
|
XML Java 数据库连接
MyBatis 解决上篇的参数绑定问题以及XML方式交互
MyBatis 解决上篇的参数绑定问题以及XML方式交互
8 0
|
21天前
|
XML Java 数据库连接
Javaweb之Mybatis的XML配置文件的详细解析
Javaweb之Mybatis的XML配置文件的详细解析
18 0
|
2月前
|
Java 数据库连接 mybatis
Mybatis+mysql动态分页查询数据案例——Mybatis的配置文件(mybatis-config.xml)
Mybatis+mysql动态分页查询数据案例——Mybatis的配置文件(mybatis-config.xml)
20 1
|
2月前
Mybatis+mysql动态分页查询数据案例——配置映射文件(HouseDaoMapper.xml)
Mybatis+mysql动态分页查询数据案例——配置映射文件(HouseDaoMapper.xml)
17 1
|
2月前
ssm(Spring+Spring mvc+mybatis)——web.xml
ssm(Spring+Spring mvc+mybatis)——web.xml
13 0
|
2月前
|
Java Spring
ssm(Spring+Spring mvc+mybatis)Spring配置文件——applicationContext.xml
ssm(Spring+Spring mvc+mybatis)Spring配置文件——applicationContext.xml
11 0