一、联合查询
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); } } 复制代码
执行测试方法
除了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> 复制代码
再次执行测试
第二种方法是使用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:标签用来定义非主键列的映射规则
执行测试
联合查询
由于实体类和数据库表是一一对应的,当进行联合查询时没有哪一个实体类可以与联合查询的结果一一对应,这时就可以使用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); } } 复制代码
执行测试
上述方式使用到了级联属性,而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:指定对象的类型
再次执行测试
一对多查询
在数据库表中新增数据一个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); }