目录
数据库表的三种关系
-
一对一关系
一对一顾名思义,比如一个人只能有一个身份证号,一个身份证号只能对应一个人,这就是一对一关系。
-
一对多关系
一对多关系,比如一公司部门有多个职员,但一个职员只能属于一个公司部门,这是一对多关系。
-
多对多关系
多对多关系,比如一个学生可以选多个课程,一门课程也可以有多个学生上课,这种的属于多对多关系。
实现多表查询的步骤
- 创建两张表
- 创建两个实体类,与所建的表中字段名称相同
- 建立两个配置文件
- 实现配置,进行查询
MyBatis中的一对一、一对多查询
1. 先创建两张表,我这里创建的是Account账户表和mbuser用户表
2. 然后创建两个对应的实体类,这两个实体类在一对一或一对多的关系中:
从表实体应该包含一个主表实体的引用,主表应该包含从表的实体集合的引用
User实体类:
package edu.xatu.Domain;
import java.util.Date;
import java.util.List;
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String adress;
//主表应该包含从表的实体集合的引用
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", adress='" + adress + '\'' +
'}';
}
}
Account实体类:
package edu.xatu.Domain;
import java.io.Serializable;
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//从表实体应该包含一个主表实体的引用
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.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;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
'}';
}
}
然后在Dao包下分别创建两个对应的接口文件及方法
UserImpl文件:
package edu.xatu.Dao;
import edu.xatu.Domain.User;
import java.util.List;
public interface UserImpl {
//查询所有用户,包含用户的账户信息
List<User> findAllUser();
}
AccountImpl文件:
package edu.xatu.Dao;
import edu.xatu.Domain.Account;
import edu.xatu.Domain.UserAccount;
import java.util.List;
public interface AccountImpl {
//查询所有账户,并且包含用户名和地址信息
List<UserAccount> findAllAccount();
}
3. 创建两个相应的配置文件
UserImpl.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="edu.xatu.Dao.UserImpl">
<!--定义包含账户信息的所有用户的resultMap-->
<resultMap id="allUserMap" type="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="adress" column="adress"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!--配置user对象中accounts集合的映射-->
<collection property="accounts" ofType="Account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
<--查询所有用户,包含用户的账户信息-->
<select id="findAllUser" resultMap="allUserMap">
select u.*,a.id as aid,a.uid,a.money from mbuser u left outer join account a on u.id=a.uid
</select>
</mapper>
AccountImpl.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="edu.xatu.Dao.AccountImpl">
<!--定义封装返回账户信息和用户名称地址的resultMap-->
<resultMap id="UserAccountMap" type="Account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--一对一关系映射:配置封装user内容-->
<association property="user" column="uid" javaType="edu.xatu.Domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="adress" column="adress"></result>
</association>
</resultMap>
<!--查询所有账户包含用户名和地址信息-->
<select id="findAllAccount" resultType="edu.xatu.Domain.UserAccount">
select a.*,u.username,u.adress from account a,mbuser u where u.id=a.uid
</select>
</mapper>
4. 可以测试一下上面的两个查询方法了
第一个:查询所有账户并且包含账户对应用户的用户名和地址信息
package edu.xatu.Test;
import edu.xatu.Dao.AccountImpl;
import edu.xatu.Domain.Account;
import edu.xatu.Domain.UserAccount;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class accountTest {
private InputStream in;
private SqlSession session;
private AccountImpl accountDao;
@Before
public void init() throws IOException {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
session = factory.openSession(true);
accountDao = session.getMapper(AccountImpl.class);
}
@After
public void destroy() throws IOException {
session.commit();
session.close();
in.close();
}
@Test
public void testFindAllAccount(){
List<UserAccount> accounts = accountDao.findAllAccount();
for (UserAccount u:accounts) {
System.out.println(u);
}
}
}
第二个:查询所有用户并且包含其账户信息(不是每个用户都有账户)
//测试查询所有用户,并包含账户信息
@Test
public void testFindAll(){
List<User> users = userImpl.findAllUser();
for(User user:users){
System.out.println("----------------------------------------------");
System.out.println(user);
System.out.println(user.getAccounts());
}
}
MyBatis中的多对多查询
多对多查询与上面步骤一样,但区别在于需要借助一个中间表来实现。
于是此处将测试多对多的数据库表本别是:用户表,角色表,和一个中间表
(因为一个用户可以扮演多个角色,而一个角色可能有多个人担任,所以是符合多对多的关系的)
1. 首先创建两张表:角色表和中间表,因为用户表就继续使用上面已有的表了,比较懒 ~
2. 然后同样写role和user的实体类及接口roleImpl
package edu.xatu.Domain;
import java.io.Serializable;
import java.util.List;
public class Role implements Serializable {
private Integer roleId;
private String roleName;
private String roleDesc;
//多对多关系映射:一个角色可以多个用户
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleDesc() {
return roleDesc;
}
public void setRoleDesc(String roleDesc) {
this.roleDesc = roleDesc;
}
@Override
public String toString() {
return "Role{" +
"roleId=" + roleId +
", roleName='" + roleName + '\'' +
", roleDesc='" + roleDesc + '\'' +
'}';
}
}
package edu.xatu.Domain;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String adress;
//多对多关系映射:一个用户可以扮演多个角色
private List<Role> roles;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", adress='" + adress + '\'' +
'}';
}
}
package edu.xatu.Dao;
import edu.xatu.Domain.Role;
import java.util.List;
public interface RoleImpl {
//查询所有演员表role
List<Role> findAllRole();
}
3. 然后写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="edu.xatu.Dao.RoleImpl">
<!--定义包含账户信息的所有用户的resultMap-->
<resultMap id="allRoleMap" type="edu.xatu.Domain.Role">
<id column="rid" property="roleId"></id>
<result column="role_name" property="roleName"></result>
<result column="role_desc" property="roleDesc"></result>
<collection property="users" ofType="edu.xatu.Domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="adress" column="adress"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</collection>
</resultMap>
<!--查询所有-->
<select id="findAllRole" resultMap="allRoleMap">
select u.*,r.id as rid,r.role_name,r.role_desc from role r
left outer join user_role ur on r.id=ur.rid
left outer join user u on u.id=ur.uid
</select>
</mapper>
4. 最后测试一下这个查询方法
@Test
public void testFindAll(){
List<Role> roles = roleImpl.findAllRole();
for(Role role:roles){
System.out.println(role);
System.out.println(role.getUsers());
}
}
至于查询所有用户及其扮演的角色的操作,与上面类似所以就不写了~
另外在创建表的时候有关于关联外键的操作,而创建包含外键的表因为我当时写了但没保存,创建完表就把那些语句删掉了,所以如果关于数据库表的相关东西不清楚的可以参考下面这某位大佬的内容,写的比较详细:
https://www.cnblogs.com/xdyixia/p/9368204.html
动态SQL的使用
1. if标签语句
if标签用来实现根据条件拼接sql语句,下面示例用来判断参数如果不为null,则拼接sql
<!--根据条件查询-->
<select id="findbyCondition" resultMap="userMap" parameterType="edu.xatu.Domain.User">
select * from mbuser where
<if test="username != null">
and username = #{username}
</if>
</select>
但是从这段代码中很容易发现,但是上面的SQL中如果传入的参数userame为null,则解析出错误的语句:select * from mbuser where and description like CONCAT(CONCAT('%', ?),'%') ,解决这个问题,需要用到where标签
2. where标签语句
<!--根据条件查询-->
<select id="findbyCondition" resultMap="userMap" parameterType="edu.xatu.Domain.User">
select * from mbuser
<where>
<if test="username != null">
and username = #{username}
</if>
<if test="sex != null">
and sex = #{sex}
</if>
</where>
</select>
表面上来看,就是多了个where标签而已。
不过实质上, mybatis是对它做了处理,当它遇到AND或者OR这些,它知道怎么处理。
3. foreach标签语句
<select id="findbyQuery" resultMap="userMap" parameterType="edu.xatu.Domain.Queryvo">
select * from mbuser
<where>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id in(" close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
java中有for, 可通过for循环, 同样, mybatis中有foreach, 可通过它实现循环,循环的对象当然主要是java容器和数组。
4. sql标签---抽取重复的SQL语句
比如:酱紫~