Многостоловая операция MyBatis
Изучив базовое добавление, удаление, изменение и запрос MyBatis, в реальных проектах мы часто сталкиваемся с операциями с несколькими таблицами. Что такое несколько таблиц? В реальной жизни часто существует связь между каждым объектом и Наш проект опирается на базу данных, чтобы связать отношения между этими сущностями для реализации нашего бизнеса, поэтому в этой части мы сосредоточимся на том, как использовать инфраструктуру MyBatis для обработки связи между несколькими таблицами данных, чтобы помочь нам лучше понять базу данных и отношения сопоставления.
(1) Связь между таблицами
А: много
-
Пользователи и заказы/финансовые продукты
- Пользователь может купить несколько партий финансовых продуктов
-
Отделы и сотрудники
- В отделе может быть много сотрудников
Б: многие к одному
-
Заказы и пользователи
- Несколько заказов принадлежат одному пользователю
С: многие ко многим
-
Выбор студенческого курса и студенты
- Студент может выбрать несколько курсов, а курс может быть выбран несколькими студентами.
Д: один к одному
-
удостоверения личности, паспорта и т. д.
- Документ может принадлежать только одному человеку
Видно, что во второй главе мы напрямую ввели содержимое бизнес-таблицы.Из-за предвосхищения предыдущих статей я не объяснял соответствующую информацию о пользователе.Единственное отсутствующее содержимое - это класс сущности пользователя и соответствующий XML-файл сопоставления. Это очень просто и соответствует тестовому классу
(2) Создайте таблицу в соответствии с бизнесом
В этой статье мы используем учетную связь между пользователями и учетными записями, а именно:
- Пользователь может иметь несколько учетных записей, учетная запись может принадлежать только одному пользователю, а также несколько учетных записей могут принадлежать одному пользователю.
Сначала вам нужно создать две таблицы: таблицу пользователей и таблицу учетных записей.
- Пусть у них есть отношения «один ко многим», нам нужно добавить внешний ключ в таблицу учетных записей.
Пользовательская таблица
CREATE TABLE USER (
`id` INT(11)NOT NULL AUTO_INCREMENT,
`username` VARCHAR(32) NOT NULL COMMENT '用户名',
`telephone` VARCHAR(11) NOT NULL COMMENT '手机',
`birthday` DATETIME DEFAULT NULL COMMENT '生日',
`gender` CHAR(1) DEFAULT NULL COMMENT '性别',
`address` VARCHAR(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
Таблица счетов
CREATE TABLE `account` (
`ID` int(11) NOT NULL COMMENT '编号',
`UID` int(11) default NULL COMMENT '用户编号',
`MONEY` double default NULL COMMENT '金额',
PRIMARY KEY (`ID`),
KEY `FK_Reference_8` (`UID`),
CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
(3) Таблица счетов — запрос одной таблицы
Сначала создайте соответствующий класс сущности Account
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
......对应 get set 方法
}
Добавьте все методы запроса в свой интерфейс AccountMappre.
public interface AccountMapper {
/**
* 查询所有账户
* @return
*/
List<Account> findAll();
}
Добавьте его файл сопоставления, примечание: опустите часть импортированного кода в заголовке.
<mapper namespace="cn.ideal.mapper.AccountMapper">
<!-- 根据查询所有用户 -->
<select id="findAll" resultType="Account">
select * from account
</select>
</mapper>
Или к более многословному,resultType="Account"
Вот потому что мы уже играли псевдоним в основном файле конфигурации, поэтому вы можете использовать названия классов под пакетом. Если вы не понимаете друзей, используйте имя полного класса.
есть тест:
/**
* 测试查询所有
*/
@Test
public void testFindAll(){
List<Account> accounts = accountMapper.findAll();
for (Account account : accounts){
System.out.println(account);
}
}
Взгляните на эффект:
(4) Индивидуальный запрос учетной записи
Как запросить информацию в Acount и отобразить соответствующие данные в соответствии со значением идентификатора пользователя.На самом деле, в основном необходимо изменить способ написания SQL.Попробуем сначала в локальном MySQL.
SELECT FROM account a,user u WHERE u.id=a.uid;
Результаты
Результат вышел, но атрибут id в таблице пользователей совпадает с именем атрибута id в таблице аккаунтов, поэтому он автоматически алиасуется, лучше задать соответствующий алиас самостоятельно.
SELECT u.*,a.id as aid,a.uid,a.money FROM account a,user u WHERE u.id=a.uid;
Это выглядит намного более организованным
На этом шаге мы можем реализовать такую функцию в коде, то есть запрашивая информацию об учетной записи, и в то же время запрашивая соответствующую информацию о пользователе, тогда из-за времени регистрации, пола и другой информации я не хочу, что мне делать? Мы можем добавить немного больше ограничений, информация о пользователе отображает только два поля: имя и адрес.
A: Способ создания подклассов (не слишком распространенный)
(1) Изменить интерфейс учетной записи
/**
* 查询所有账户,并且带有用户名称和地址信息
* @return
*/
List<UserAccount> findAllAccount();
Вы могли заметить, что возвращаемый нами тип списка — UserAccount, почему?
Поскольку информация, которую мы хотим вернуть, должна содержать информацию в двух таблицах, кажется, что у нас нет объекта, который может нести столько информации, поэтому мы создаем класс UserAccount.
(2) Создать класс UserAccount
public class UserAccount extends Account {
private String username;
private String address;
......对应 get set 方法
@Override
public String toString() {
return super.toString() + " UserAccount{" +
"username='" + username + '\'' +
", address='" + address + '\'' +
'}';
}
}
Описание: Поскольку нам нужно только показать имя и обратиться только к этим двум полям, поэтому нужно только создать имя пользователя и обратиться к двум полям, и мы можем легко вызвать наследуемый запрос вывода учетной записи в информацию в учетной записи
(3) Изменить AccountMapper.xml
<select id="findAllAccount" resultType="UserAccount">
select a.*,u.username,u.address from account a , user u where u.id = a.uid;
</select>
(4) Тестовый код
/**
* 查询所有账户,并且带有用户名称和地址信息
* @return
*/
@Test
public void testFindAllAccount(){
List<UserAccount> uas = accountMapper.findAllAccount();
for (UserAccount ua : uas ){
System.out.println(ua);
}
}
(5) Эффект исполнения
B: Установление отношений между классами объектов (рекомендуется)
(1) Изменить интерфейс учетной записи
/**
* 查询所有账户
* @return
*/
List<Account> findAll();
(2) Изменить класс аккаунта
В классе учетной записи необходимо добавить ссылку на объект пользователя, которая является основной таблицей, соответствующей нашему пользователю
//从表实体应该包含一个主表实体的对象引用
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
(3) Изменить AccountMapper.xml
<!-- 定义封装 Account和User 的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="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="telephone" column="telephone"></result>
<result property="birthday" column="birthday"></result>
<result property="gender" column="gender"></result>
<result property="address" column="address"></result>
</association>
</resultMap>
<!-- 根据查询所有用户 -->
<select id="findAll" resultMap="userAccountMap">
SELECT u.*,a.id AS aid,a.uid,a.money FROM account a,user u WHERE u.id = a.uid;
</select>
Описание: поскольку результат, который мы хотим вернуть, представляет собой несколько значений, не существует класса инкапсуляции, полностью соответствующего возвращаемому значению результата для получения, поэтому мы можем использовать resultMap, предоставленный MyBatis, для получения данных результата, которые будут в имени столбца. и Создать отношение сопоставления между именами атрибутов класса-оболочки Java. Основное внимание в этой статье по-прежнему уделяется работе с таблицей. Об этой проблеме вы можете написать статью, чтобы объяснить ее позже. Если вам это не ясно. часть, вы можете проверить это сами Значение этих надписей на самом деле не так уж сложно
(4) Тестовый код
/**
* 测试查询所有
*/
@Test
public void testFindAll(){
List<Account> accounts = accountMapper.findAll();
for (Account account : accounts){
System.out.println("--------------------------");
System.out.println(account);
System.out.println(account.getUser());
}
}
(5) Эффект исполнения
(5) Пользовательский запрос «один ко многим»
(1) Изменить интерфейс UserMapper
/**
* 查询所有用户信息,同时显示出该用户下的所有账户
*
* @return
*/
List<User> findAll();
(2) Изменить класс пользователя
Член коллекции должен быть добавлен в класс Java, тип — Account, чтобы мы могли нести информацию об учетной записи.
//一对多关系映射,主表实体应该包含从表实体的集合引用
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
(3) Изменить AccountMapper.xml
<!-- 定义User的resultMap-->
<resultMap id="userAccountMap" type="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="telephone" column="telephone"></result>
<result property="birthday" column="birthday"></result>
<result property="gender" column="gender"></result>
<result property="address" column="address"></result>
<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="findAll" resultMap="userAccountMap">
SELECT * FROM user u LEFT OUTER JOIN account a on u.id = a.uid;
</select>
Примечание:LEFT OUTER JOIN
: Левое внешнее соединение, вы можете отобразить все данные в левой таблице
(4) Тестовый код
/**
* 测试查询所有
*/
@Test
public void testFindAll() {
List<User> users= userMapper.findAll();
for (User user : users) {
System.out.println("--------------------------");
System.out.println(user);
System.out.println(user.getAccounts());
}
}
(5) Эффект исполнения
Видно, что вся информация о пользователе выведена на печать (рис взята только с лицевой части), а информация о наличии всех учетных записей пользователей в распечатке
(6) Операция «многие ко многим»
Мы уже читали это раньше, отношения «один ко многим» между пользователями и учетными записями. Давайте изучим ситуацию «многие ко многим». В этом случае ситуация будет более хлопотной. Например, давайте возьмем пример: отношения между пользователи и должности
- У пользователя может быть несколько заданий, а задание может принадлежать нескольким пользователям.
Но как соединить две таблицы? Для этого требуется промежуточная таблица, чтобы установить связь между двумя таблицами.
Сначала создайте список вакансий
CREATE TABLE `role` (
`ID` int(11) NOT NULL COMMENT '编号',
`ROLE_NAME` varchar(30) default NULL COMMENT '职位',
`ROLE_DESC` varchar(60) default NULL COMMENT '描述',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `role`(`ID`,`ROLE_NAME`,`ROLE_DESC`) values (1,'班主任','管理整个班'),(2,'院长','管理整个学院'),(3,'校长','管理整个学校');
Затем создаем промежуточную таблицу
CREATE TABLE `user_role` (
`UID` int(11) NOT NULL COMMENT '用户编号',
`RID` int(11) NOT NULL COMMENT '职位编号',
PRIMARY KEY (`UID`,`RID`),
KEY `FK_Reference_10` (`RID`),
CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `role` (`ID`),
CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user_role`(`UID`,`RID`) values (12,1),(16,1),(12,2);
Как пользовательская таблица, мы все еще погрязли в предыдущем пользователе
A: Запросить всю информацию о работе
(1) Создать сущность
public class Role implements Serializable {
private Integer roleId;
private String roleName;
private String roleDesc;
...... 省略对应 get set toString 方法
}
(2) Создайте интерфейс и добавьте методы
public interface RoleMapper {
/**
* 查询所有职位
* @return
*/
List<Role> findAll();
}
(3) Создайте файл RoleMapper.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.ideal.mapper.RoleMapper">
<!-- 定义Role的resultMap-->
<resultMap id="roleMap" type="Role">
<id property="roleId" column="id"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
</resultMap>
<!-- 根据查询所有用户 -->
<select id="findAll" resultMap="roleMap">
SELECT * FROM role
</select>
</mapper>
Следует отметить, что значение в столбце — это имя поля в базе данных, а значение в свойстве — соответствующая переменная-член в JavaBean.Поскольку имена двух не совпадают, обратите внимание на различие
(4) Тестовый код
@Test
public void testFindAll(){
List<Role> roles = roleMapper.findAll();
for (Role role : roles){
System.out.println("-----------------------");
System.out.println(role);
}
}
(5) Эффект исполнения
B: роль запроса для получения соответствующих позиций
(1) Изменить класс ролей
Добавьте коллекцию List типа User в класс сущности Role.
//多对多关系映射,一个职位可以拥有多个用户
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
Мы по-прежнему используем метод интерфейса, который мы создали ранее, метод findAll
(2) Изменить RoleMapper.xml
В этой части нет сомнений, что необходимо создать resultMap of Role, а другая часть — это написание соответствующего SQL-оператора.
Нам нужно написать SQL-заявления простой анализ, сначала посмотрите на отношения между тремя таблицами
Промежуточная таблица связывает таблицы пользователей и ролей соответственно через два поля UID RID.
Сначала найдите избавление промежуточной таблицы по идентификатору в таблице ролей, а затем найдите значение идентификатора в пользовательской таблице по значению uid, соответствующему избавлению, чтобы получить соответствующую информацию о пользователе.
На данный момент нам нужны два левых внешних соединения, код xml выглядит следующим образом
<mapper namespace="cn.ideal.mapper.RoleMapper">
<!-- 定义Role的resultMap-->
<resultMap id="roleMap" type="Role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
<collection property="users" ofType="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="telephone" column="telephone"></result>
<result property="birthday" column="birthday"></result>
<result property="gender" column="gender"></result>
<result property="address" column="address"></result>
</collection>
</resultMap>
<!-- 根据查询所有用户 -->
<select id="findAll" resultMap="roleMap">
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>
(3) Тестовый код
@Test
public void testFindAll(){
List<Role> roles = roleMapper.findAll();
for (Role role : roles){
System.out.println("---------------------");
System.out.println(role);
System.out.println(role.getUsers());
}
}
(4) Эффект исполнения
C: Запрос заданий Получить соответствующего пользователя
(1) Изменить метод интерфейса
public interface UserMapper {
/**
* 查询所有用户信息,同时显示出该用户下的所有账户
*
* @return
*/
List<User> findAll();
}
(2) Изменить объекты пользователя
Это сопоставление отношений «многие ко многим», пользователь может иметь несколько ролей.
private List<Role> roles;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
(3) Изменить RoleMapper.xml
<mapper namespace="cn.ideal.mapper.RoleMapper">
<!-- 定义Role的resultMap-->
<resultMap id="roleMap" type="Role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
<collection property="users" ofType="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="telephone" column="telephone"></result>
<result property="birthday" column="birthday"></result>
<result property="gender" column="gender"></result>
<result property="address" column="address"></result>
</collection>
</resultMap>
<!-- 根据查询所有用户 -->
<select id="findAll" resultMap="roleMap">
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<User> users = userMapper.findAll();
for (User user : users){
System.out.println("---------------------");
System.out.println(user);
System.out.println(user.getRoles());
}
}
(5) Эффект исполнения
конец
Если в статье есть какие-либо недостатки, пожалуйста, оставьте сообщение для обмена, спасибо за вашу поддержку!
Если это может вам помочь, то следуйте за мной! Если вы предпочитаете читать статьи WeChat, вы можете подписаться на мой публичный аккаунт.
Мы здесь незнакомцы, но мы все усердно работаем для своей мечты ❤
Публичный аккаунт, настаивающий на размещении оригинальных технических статей о разработке: в идеале — более двух дней.