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);
}



相关文章
|
9天前
|
SQL 人工智能 Java
mybatis-plus配置sql拦截器实现完整sql打印
_shigen_ 博主分享了如何在MyBatis-Plus中打印完整SQL,包括更新和查询操作。默认日志打印的SQL用?代替参数,但通过自定义`SqlInterceptor`可以显示详细信息。代码示例展示了拦截器如何替换?以显示实际参数,并计算执行时间。配置中添加拦截器以启用此功能。文章提到了分页查询时的限制,以及对AI在编程辅助方面的思考。
43 5
mybatis-plus配置sql拦截器实现完整sql打印
|
1天前
|
SQL XML 数据库
后端数据库开发高级之通过在xml文件中映射实现动态SQL
后端数据库开发高级之通过在xml文件中映射实现动态SQL
8 3
|
1天前
|
SQL XML Java
后端数据库开发JDBC编程Mybatis之用基于XML文件的方式映射SQL语句实操
后端数据库开发JDBC编程Mybatis之用基于XML文件的方式映射SQL语句实操
12 3
|
1天前
|
SQL Java 数据库连接
2万字实操案例之在Springboot框架下基于注解用Mybatis开发实现基础操作MySQL之预编译SQL主键返回增删改查
2万字实操案例之在Springboot框架下基于注解用Mybatis开发实现基础操作MySQL之预编译SQL主键返回增删改查
8 2
|
12天前
|
SQL XML Java
MyBatis动态SQL------------------choose用法
MyBatis动态SQL------------------choose用法
19 1
|
20小时前
|
XML 关系型数据库 数据库
使用mybatis-generator插件生成postgresql数据库model、mapper、xml
使用mybatis-generator插件生成postgresql数据库model、mapper、xml
8 0
|
1天前
|
SQL Java 数据库连接
Mybatis动态SQL语句总结
Mybatis动态SQL语句总结
|
4天前
|
SQL Java 数据库连接
【MyBatis】MyBatis操作数据库(二):动态SQL、#{}与${}的区别
【MyBatis】MyBatis操作数据库(二):动态SQL、#{}与${}的区别
9 0
|
6天前
|
SQL Java 数据库连接
JavaWeb基础第三章(MyBatis的应用,基础操作与动态SQL)
JavaWeb基础第三章(MyBatis的应用,基础操作与动态SQL)
|
12天前
|
SQL Java 数据库连接
MyBatis SQL 批量更新(代码➕案例)
MyBatis SQL 批量更新(代码➕案例)
33 0