#MyBatis多表查询 #多对一、一对多的两种实现方式 @FDDLC
方式一(常用):
我们知道,一个用户可以对应多个账户,一个账户只能对应一个用户,即账户和用户之间存在多对一的关系。为了表示这种关系,在账户类中额外增加一个用户类的成员:
对应的mapper配置如下:
<?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="cn.liuxingchang.dao.AccountDao"> <resultMap id="accountWithUser" type="cn.liuxingchang.domain.Account"> <id property="id" column="id" /> <result property="uid" column="uid" /> <result property="money" column="money" /> <association property="user" javaType="cn.liuxingchang.domain.User"> <id property="id" column="user_id" /> <result property="name" column="name" /> <result property="age" column="age" /> </association> </resultMap> <select id="findAll" resultMap="accountWithUser"> select a.*, u.id as user_id, name, u.age from account a, user u where a.uid = u.id </select> </mapper>
为了对多表查询结果的封闭,先定义了一个<resultMap>,然后在<select>标签里使用。这里的难点是<resultMap>的书写。id、money、uid都好理解,可能疑惑的地方是怎么给Account类里的user成员赋值。如你所见,用了个association标签!
association的property是user好理解,但没有column属性,即数据表中没有对应的列名。没有column,但多了个javaType,其实又相当于来了个javaType到相应数据表的映射,即这个association标签相当于是专用于内嵌的<resultMap>标签!
这里补充几个注意事项:
1、如果在SQL语句中字段取了别名的话,column属性也应该填别名,而不能是原字段名。
2、表取了别名后,别名可以随便用;字段取了别名后在where条件里却只能用原字段名,而不能用别名。
方式二(不常用):使用继承(也可以直接把Account类和User类的部分或全部属性合并)
对应的ExtendedAccount类:
对应的SQL配置:
<select id="findAll2" resultType="cn.liuxingchang.domain.ExtendedAccount"> select a.*, name, u.age from account a, user u where a.uid = u.id </select>
说明:
1、用的是resultType属性而非像方式一那样必须使用resultMap。
2、account表中的uid和user表中的id是一样的,故只保留了uid。
最后附上源码:
项目结构:
数据库的相关信息:
MySQL:8.0.16 port:3306 database:multi_table
account表:
user表:
Account类:
package cn.liuxingchang.domain; import java.io.Serializable; public class Account implements Serializable { private Integer id; private Integer uid; private Double money; private User user; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getUid() { return uid; } public void setUid(Integer uid) { this.uid = uid; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String toString() { return "Account{" + "id=" + id + ", uid=" + uid + ", money=" + money + ", user=" + user + '}'; } }
ExtendedAccount类:
package cn.liuxingchang.domain; public class ExtendedAccount extends Account { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return super.toString() + " ### " + "ExtendedAccount{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
User类:
package cn.liuxingchang.domain; import java.io.Serializable; public class User implements Serializable { private Integer id; private String name; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
AccountDao接口:
package cn.liuxingchang.dao; import cn.liuxingchang.domain.Account; import cn.liuxingchang.domain.ExtendedAccount; import java.util.List; public interface AccountDao { List<Account> findAll(); List<ExtendedAccount> findAll2(); }
AccountMapper.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="cn.liuxingchang.dao.AccountDao"> <resultMap id="accountWithUser" type="cn.liuxingchang.domain.Account"> <id property="id" column="id" /> <result property="uid" column="uid" /> <result property="money" column="money" /> <association property="user" javaType="cn.liuxingchang.domain.User"> <id property="id" column="user_id" /> <result property="name" column="name" /> <result property="age" column="age" /> </association> </resultMap> <select id="findAll" resultMap="accountWithUser"> select a.*, u.id as user_id, name, u.age from account a, user u where a.uid = u.id </select> <select id="findAll2" resultType="cn.liuxingchang.domain.ExtendedAccount"> select a.*, name, u.age from account a, user u where a.uid = u.id </select> </mapper>
mybatis.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/multi_table?characterEncoding=UTF8&serverTimezone=Asia/Shanghai"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mapper/AccountMapper.xml" /> </mappers> </configuration>
pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>P074_MyBatis_Many2One</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
Test.java:
import cn.liuxingchang.dao.AccountDao; import cn.liuxingchang.domain.Account; import cn.liuxingchang.domain.ExtendedAccount; 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.After; import org.junit.Before; import java.io.InputStream; import java.util.List; public class Test { private InputStream in; private SqlSessionFactory factory; private SqlSession sqlSession; private AccountDao accountDao; @Before public void before() throws Exception { in = Resources.getResourceAsStream("mybatis.xml"); factory = new SqlSessionFactoryBuilder().build(in); sqlSession = factory.openSession(); accountDao = sqlSession.getMapper(AccountDao.class); } @After public void after() throws Exception { sqlSession.commit(); sqlSession.close(); in.close(); } @org.junit.Test public void findAllTest() { List<Account> accounts = accountDao.findAll(); for (Account account: accounts) { System.out.println(account); } } @org.junit.Test public void findAll2Test() { List<ExtendedAccount> extendedAccounts = accountDao.findAll2(); for(ExtendedAccount extendedAccount: extendedAccounts) { System.out.println(extendedAccount); } } }