MyBatis中文官网 - 2018年3月
type: channel
link: http://www.mybatis.cn/2018/03/
description: 专注于MyBatis框架、SQL知识、Java校招/面试
items: MyBatis trim 标签
items: MyBatis bind 标签
items: MyBatis foreach 标签
items: MyBatis set 标签
items: MyBatis where 标签
items: MyBatis choose、when、otherwise 标签
items: MyBatis if 标签
items: MyBatis的多对多关联关系
items: MyBatis的一对多关联关系
items: MyBatis的一对一关联关系

MyBatis trim 标签
type: item
date: 2018-03-27T06:27:00+00:00
description: 备注：本文修订于2022年6月29日。1、MyBatis trim 标签Mybatis具有实现动态SQL的能力，但是在拼凑SQL语句的时候，稍有不注意则会画蛇添足，此时可以通过 trim 标签来进行修剪。trim 是“修剪”的意思，其基本格式如下：<trim prefix="" suffix="" suffixOverrides="" prefixOverrides=""></trim>trim 标签的主要属性有四个，如下表所示： 属性名 作用 prefix 给sql增加前缀 suffix 给sql增加后缀 prefixOverrides 去掉sql前面多余的关键字或者字符 suffixOverrides 去掉sql后面多余的关键字或者字符 2、prefix 使用场景介绍 select * from t_users <trim prefix="where"> name = #{name} and age = #{age} and phone = #{phone} </trim> 在动态生成SQL的过程中，会将prefix前缀拼接到trim标签的外侧，最终得到的SQL如下：select * from t_users where name= ? and age= ? and phone = ?3、prefixOverrides 使用场景介绍 select * from t_users <trim prefix="where"> <if test="name != null"> name=#{name} </if> <if test="age != null"> and age=#{age} </if> <if test="phone != null"> and phone=#{phone} </if> </trim> 在动态 SQL 的拼接过程中，如果 name 为 null，则第一个 if 不成立，里面的 SQL 语句不拼接，第二个 if 里面的 and 会紧跟在 where 后面，造成语法错误，最终动态生成的 SQL 如下：select * from t_users where and age = ? and phone = ?为了解决这个问题，只要加上 prefixOverrides 即可： select * from t_users <trim prefix="where" prefixOverrides="and"> <if test="name != null"> name=#{name} </if> <if test="age != null"> and age=#{age} </if> <if test="phone != null"> and phone=#{phone} </if> </trim> 当然，prefix 和 prefixOverrides 可以放在一起综合使用，如下所示：select * from t_users <trim prefix="WHERE" prefixOverrides="AND|OR"> <if test="name != null and name.length() > 0"> AND name=#{name}</if> <if test="gender != null and gender.length() > 0"> AND gender=#{gender}</if> </trim>假如name和gender的值都不为null，打印出的SQL是这样的：select * from t_users where name = ? and gender = ?where后不存在and，这是因为prefixOverrides="AND|OR"代表去掉第一个and或者是or。4、suffix 和 suffixOverrides 使用场景介绍update t_users <trim prefix="set" suffixOverrides="," suffix=" where id = #{id} "> <if test="name != null and name.length() > 0"> name=#{name}, </if> <if test="gender != null and gender.length() > 0"> gender=#{gender}, </if> </trim>假如name和gender的值都不为null，打印出的SQL为：update t_users set name = ? , gender = ? where id = ?trim 标签的作用是：在 gender = ? 后面裁剪了逗号，而且自动加了一个 set 前缀和 where 后缀。5、提醒…

MyBatis bind 标签
type: item
date: 2018-03-27T01:26:00+00:00
description: 1、MyBatis bind 标签的作用bind 标签可以用来在映射文件中定义变量，然后将输入参数中的值拼接其他字符串后组成新的字符串赋值给该变量。2、MyBatis bind 标签的应用场景bind 标签最常用的场景是模糊查询。3、MyBatis bind 标签的使用过程第一步：编写接口。public List<Employee> selectEmployeeLikeName(Employee e){}第二步：设置变量。bind 标签可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。如下所示： <bind name="pattern" value="'%'+_parameter.getName() + '%'" /> SELECT * FROM tb_employee WHERE loginname LIKE #{pattern} 备注：参数名称必须是_parameter，表示传入的查询对象Employee，否则会提示异常。第三步：设置查询参数。// 根据传入的参数进行模糊查询 List<Employee> selectEmployeeLikeName(Employee employee); public void testSelectEmployeeLikeName(SqlSession session) { EmployeeMapper em = session.getMapper(EmployeeMapper.class); Employee employee = new Employee(); // 设置模糊查询的参数 employee.setName("o"); List<Employee> list = em.selectEmployeeLikeName(employee); System.out.println(list); }测试selectEmployeeLikeNtme方法，控制台显示如下:DEBUG [main]==> Preparing: SELECT * FROM tb_ employee WHERE loginname LIKE ? DEBUG [main]==> Parameters :%o%(String) DEBUG [main]==> Total :2 Employee [id=2,loginname=rose,password=123456,name=露丝,sex=女,age=21,phone=13902018888,sal=6800.0,state=ACTIVE] Employee [id=3,loginname=tom,password=123456,name=汤姆,sex=男,age=25,phone=13902017777,sal=8800.0,state=ACTIVE]可以看到，执行的sql语句是一个like模糊查询语句，返回的是loginname中包含“o”的所有数据。

MyBatis foreach 标签
type: item
date: 2018-03-27T00:29:00+00:00
description: 备注：本文修改于2022年6月28日。1、MyBatis foreach 标签介绍foreach 标签主要用在构建 in 条件中，它可以在 SQL 语句中遍历一个集合。2、MyBatis foreach 标签属性foreach 标签的属性主要有 collection，item，index，open，separator，close。其含义如下所示：collection：遍历的对象。当遍历对象是List、Array对象时，collection属性值分别默认用"list"、"array"代替，而Map对象没有默认的属性值。注意：可以使用 @Param(“keyName”) 注解来自定义collection属性值，设置keyName后，list、array会失效。item：集合元素遍历时的别名称。该参数为必选项。index：在list、array中，index为元素的序号索引，但是在Map中，index为遍历元素的key值。该参数为可选项。open：遍历集合时的开始符号，通常与 close=")" 搭配使用。使用场景为 IN()、values()时。该参数为可选项。separator：元素之间的分隔符，类比在 IN() 的时候，separator=","，最终所有遍历的元素将会以设定的逗号符号隔开。该参数为可选项。close：遍历集合时的结束符号，通常与 open="(" 搭配使用。该参数为可选项。3、collection 属性值的三种情况如果参数类型为List时，collection的默认属性值为list，同样可以使用@Param注解自定义;如果参数类型为Array时，collection的默认属性值为array，同样可以使用@Param注解自定义;如果传入的参数类型为Map时，collection的属性值可为下面三种情况：遍历 map.keys遍历 map.values遍历 map.entrySet()3.1 参数类型为 List，collection 属性值为 listMapper文件：public List<User> selectByIds(List<Integer> userIds);SQL片段： select * from t_users where id in <foreach collection="list" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> 3.2 参数类型为 List，使用 @Param 注解自定义 collection 属性值Mapper文件：List<UserList> getUserInfo(@Param("userName") List<String> userName);SQL片段： SELECT * FROM t_users where <if test="userName!= null and userName.size() >0"> USERNAME IN <foreach collection="userName" item="value" separator="," open="(" close=")"> #{value} </foreach> </if> 3.3 参数类型为 Array，collection 属性值为 arrayMapper文件：public List<User> selectByIds(int[] userIds);SQL片段： select * from t_user where id in <foreach collection="array" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> 3.3 参数类型为 Array，使用 @Param 注解自定义 collection 属性值Mapper文件：List<UserList> getUserInfo(@Param("userName") String[] userName);SQL片段： SELECT * FROM t_users where <if test="userName!= null and userName.length() >0"> USERNAME IN <foreach collection="userName" item="value" separator="," open="(" close=")"> #{value} </foreach> </if> 3.3 参数类型为 Map，collection 属性值分为三种情况Mapper文件：List<UserList…

MyBatis set 标签
type: item
date: 2018-03-26T12:48:00+00:00
description: MyBatis set 标签set 标签可以被用于动态包含需要更新的列，而舍去其他的，例如多余的逗号。 SELECT * FROM tb_employee where id = #{id} <update id="updateEmployeeIfNecessary" parameterType="cn.mybatis.domain.Employee"> update tb_employee <set> <if test="loginname != null">loginname=#{loginname} ,</if> <if test="password != null">password=#{password} ,</if> <if test="name != null">name=#{name},</if> <if test="sex != null">sex=#{sex},</if> <if test="age != null">age=#{age},</if> <if test="phone != null">phone=#{phone} ,</if> <if test="sal != null">sal=#{sal},</if> <if test="state != null">state=#{state}</if> </set> where id=#{id} </update>set 标签会动态前置SET关键字，同时也会消除无关的逗号，因为使用了条件语句之后很可能就会在生成的赋值语句的后面留下这些逗号。// 根据id查询员工 Employee selectEmployeeWithId(Integer id); // 动态更新员工 void updateEmployeeIfNecessary (Employee employee);需要注意的是，updateEmployeelfNecessar方法传递的参数不是之前使用的HashMap，而是一个Employee对象，因为通常更新操作时都是先查询出一个实体对象再进行更新操作。public void testUpdateEmployeeIfNecessary(qlSession session) { EmployeeMapper em = session.getMapper(EmployeeMapper.class); // 查询id为4的员工信息 Employee employee = em.selectEmployeewithId(4); // 设置需要修改的属性 employee.setLoginname("mary"); employee.setPassword("123"); employee.setName("玛丽"); em.updateEmployeeIfNecessary(employee); }测试updateEmployeelfNecessa方法，控制台显示如下:DEBUG [main]==> Preparing: SELECT * FROM tb_ employee where id= ? DEBUG [main]==> Parameters :4 (Integer) DEBUG [main]<== Total :1 DEBUG [main]==> Preparing :update tb_employee SET loginname=?,password=?,name=?,sex=?,age=?,phone=?,sal=?,state=? where id=? DEBUG [main]==> Parameters: mary(String),123(String),玛丽(String),女(String),20(Integer),13902016666(String),5800.0(Double),ACTIVE(String),4 (Integer) DEBUG [main]<== Updates :1可以看到，首先执行了一条查询语句，查询id为4的员工，之后执行了一条update语句，根据传入的Employee对象更新员工信息。切换到数据库，可以看到id为4的员工信息已经更新。

MyBatis where 标签
type: item
date: 2018-03-23T06:11:00+00:00
description: MyBatis where 标签前面几个例子已经很好地解决了动态SQL问题。现在回到之前的if示例，这次我们将state="ACTIVE"也设置成动态的条件，看看会发生什么。 SELECT * FROM tb_employee WHERE <if test="state != null "> state= #{state} </if> <if test="id != null "> and id = #{id} </if> 如果传入state参数，则执行正常。如果没有传入参数，则会执行sql语句:SELECT * EROM tb_employee WHERE如果只是传入id，则会执行sql语句:SELECT * FROM tb_ employee WHERE and id = ?也就是说，如果没有传入state参数，会导致执行失败。这个问题不能简单地用条件语句来解决。MyBatis有一个简单的处理方法，只要简单地修改就能得到想要的效果： SELECT * EROM tb_employee <where> <if test="state != null "> state = #{state} </if> <if test="id != null "> and id = #{id} </if> <if test="loginname != null and password != null"> and loginname = #{loginname} and password = #{password} </if> </where> where 标签知道只有在一个以上的if条件有值的情况下才去插入WHERE子句。而且，若最后的内容是“AND”或“OR”开头，则where元素也知道如何将它们去除。List<Employee> selectEmployeeLike (HashMap<string,object> params) ; public void testSelectEmployeeLike(SqlSession session) { EmployeeMapper em = session.getMapper(EmployeeMapper.class); HashMap<string, Object> params = new HashMap<string, Object>(); // 设置id,loginname和password属性 params.put("id", 1); params.put("loginname", "jack"); params.put("password", "123456"); List<Employee> list = em.selectEmployeelike(params); list.forEach(employee -> System.out.printIn(employee)); } 测试selectEmployeeLike方法，控制台显示如下:DEBUG [main]==> Preparing: SELECT * FROM tb_employee WHERE id = ? and loginname= ? and password = ? DEBUG [main]==> Parameters: 1(Integer),jack(String),123456(string) DEBUG [main]==> Total: 1 Employee [id=1,paasword=12345,name=杰克,sex=男,age=26] loginnamejack, phone=13902019999,sal=9800.0,state-ACTIVE]可以看到，当没有传入 state 参数时，MyBatis 自动过滤掉 id 前面的 and 关键字。MyBatis where 标签的局限性where 标签只能去除第一个条件中出现的前置 and 关键字。像以下情况，where 就无能为力了: SELECT * EROM tb_employee <where> <if test="state != null "> state = #{state} and </if> <if test="id != null "> id = #{id} and </if> <if test="loginname != null and password != null"> loginname = #{loginname} and password = #{password} </if> </where> where 标签无法去除掉后面的 and 关键字，此时 SQL 语句出现语法错误。要想解决以上 where 标签无法处…

MyBatis choose、when、otherwise 标签
type: item
date: 2018-03-23T04:23:00+00:00
description: MyBatis choose、when、otherwise 标签有些时候，我们不想使用所有的条件语句，而只想从中择其一二。针对这种情况，MyBatis提供了choose标签，它有点像Java中的switch语句。还是上面的例子，但是这次变为：如果客户端提供了 id 就按 id 查找，提供了 loginname 和 password 就按 loginnam 和password 查找，若两者都没有提供，就返回所有sex = '男'的 Employee。 SELECT * FROM tb employee WHERE state = 'ACTIVE' <choose> <when test="id != null"> and id= #{id} </when> <when test="loginname != null and password != null"> and loginname = #{loginname} and password = #{password} </when> <otherwise> and sex = '男' </otherwise> </choose> List<Employee> selectEmployeeChoose(HashMap<String,Object> params); public void testSelectEployeeChoose(SqlSession session) { EmployeeMapper em = session.getMapper(EmployeeMapper.class); HashMap<String, Object> params = new HashMap<String, object>(); // 设置id属性 params.put("id", 1); params.put("loginnamc", "jack"); params.put("password", "123456"); List<employee> list = em.selectEmployeechoose(params); list.forEach(employee -> Systen.out.printIn(employee)); } 运行main 方法，尝试selectEmployeeChoose()方法，控制台显示如下:DEBUG [main]==> Preparing: STTR.CT FROM tb_employee WHERE state = 'ACTIVE' and loginname = ? and password = ? DEBUG [main]==> Parameters: jack(String),123456(String) DEBUG [main]==> Total :1 [Employee [id=1,loginname=jack,passwiord=123456,name=马云,sex=男,age=26,phone=13902019999,sal=9800.0,state=ACTIVE] ]可以看到，HashMap里面传递的参数包括了id、loginname和password，执行的sql语句中因为使用了choose标签，所以sql语句执行的是按照id查询，查询返回的Emplyee对象就是id为1的对象。接下来注释以下代码:// params.put("id",1) ;再次执行main方法，控制台显示如下:DEBUG [main]==> Prcparing: SEIECT * FROM tb_employee WHERE state = 'ACTIVE' and login name= ? and password = ? DEBUG [main]==> Parameters: jack(String) ,123456(String) DEBUG [main]<== Total :1 Employee [id=1,loginname=jack,passwiord=123456,name=马云,sex=男,age=26,phone=13902019999,sal=9800.0,state=ACTIVE]可以看到，HashMap里面传递的参数只包括loginname和password，所以sql语句是按照loginname和password查找，查询返回的Emplyee对象就是loginname，即jack，并且password是123456的对象。接下来注释以下代码:// params.put("id",1); // params.put("loginname","jack"); // params.put("password","123456")…

MyBatis if 标签
type: item
date: 2018-03-17T11:27:00+00:00
description: MyBatis if 标签if 标签在mybatis的开发工作中主要用于where查询、insert插入和update更新三种操作中，本文接下来会对每种操作中的 if 标签做详细讲述.where 查询中使用<if>标签:<mapper namespace="cn.mybatis.mapper.EmployeeMapper"> SELECT * FROM tb_employee WHERE state = 'ACTIVE' <if test="id != null"> and id = #{id} </if> </mapper>以上语句提供了一个可选的根据id查找Employee的功能。如果没有传入id，那么所有处于"ACTIVE"状态的Employee都会被返回。反之，若传入了id，那么就会把查找id内容的Employee结果返回。public Interface EmployeeMapper { List<Employee> selectEmployeeByIdLike (HashMap<String,Object> params); }以上代码提供了一个和EmployeeMapper.xml中的select元素的id同名的方法，需要注意的是，selectEmployeeByIdLike 接收一个 HashMap 作为参数。public static void main(string[] args) throws Exception { // 读取mybatis-config.xml 文件 Inputstream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 初始化mybatis,创建SqlSessionFactory 类的实例 sqlsessionFactory sqlSessionEactory = new sqlsessionFactoryBullder().build(inputStream); // 创建Session实例 sqlSesaion seasion = sqlsessionFactory.openSession(); DynamicsQlTest t = new DynamicSQITest(); t.testSelectEmployeeByIdLike(sesion); // 提交事务 sesion.commit(); // 关闭Session session.close(); } // 测试 public void testSelectemployeeByIdLike(Sqlsession session) { // 获得EmployeeMapper接口的代理对象 EmployeeMapper em = session.getMapper(EmployeeMapper.class); // 创建一个HashMap存储参数 HashMap<String, Object> params = new HashMap<String, Object>(); // 设置id属性 params.put("id", 1); // 调用EmployeeMapper接口的selectEmployeeByIdLike方法 List<Employee> list = em.selectEmployeeByIdLike(params); // 查看查询结果 list.foEach(employee -> System.out.printIn(employee)); } 运行上面的main方法，其通过SqlSession的getMapper(Class<T> type)方法获得mapper接口的代理对象EmployeeMapper。调用selctEmployeeByIdLike方法时会执行EmployeeMapper.xm中 元素中定义的sql语句。控制台显示如下:DEBUG [main]==> Preparing: SELBCT * FRON tb_employee WHERE state = 'ACTIVE' and id= ? DEBUG [main]==> Parameters: DEBUG [main]<== Total:2 Employee [id=1,loginname=jack,password=123456,name=马云,sex=男,age=26,phone=13900000001,sal=9800.0,state=ACTIVE]可以看到，执行的sql语句中因为传入了id属性，所以sql语句中包含了“and id= ?”，查询返回的Emplyee对象就是"id"为1的对象。接下来注释以下代码：// params.p…

MyBatis的多对多关联关系
type: item
date: 2018-03-15T10:21:00+00:00
description: 本文修订于2019年3月17日SQL脚本在实际项目开发中，多对多关系也是非常常见的关系，比如，一个购物系统中，一个用户可以有多个订单，这是一对多的关系；一个订单中可以购买多种商品，一种商品也可以属于多个不同的订单，订单和商品就是多对多的关系。对于数据库中多对多关系建议使用一个中间表来维护关系，中间表中的订单d作为外键参照订单表的id，商品id作为外键参照商品表的id。下面我们就用一个简单示例来看看MyBatis怎么处理多对多关系。首先，在数据库创建三个表：TB_USER、TB_ARTICLE和TB_ORDER，再创建一个中间表维护TB_ARTICLE和TB_ORDER的关系，并插入测试数据。SQL脚本如下:drop table if exists tb_user; -- 创建用户表 CREATE TABLE tb_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(18), loginname VARCHAR(18), PASSWORD VARCHAR(18), phone VARCHAR(18), address VARCHAR(18) ); -- 插入用户表测试数据 INSERT INTO tb_user (username,loginname,PASSWORD,phone,address) VALUES('马云','jack','123456','13600000000','杭州'); drop table if exists tb_article; -- 创建商品表 CREATE TABLE tb_article( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(18), price DOUBLE, remark VARCHAR(18) ); -- 插入商品表测试数据 INSERT INTO tb_article(NAME,price,remark) VALUES('精通Python自然语言处理',108.9,'经典著作'); INSERT INTO tb_article(NAME,price,remark) VALUES('自然语言处理原理与实践',99.9,'经典著作'); INSERT INTO tb_article(NAME,price,remark) VALUES('大数据架构详解',89.9,'经典著作'); INSERT INTO tb_article(NAME,price,remark) VALUES('推荐系统实践',69.9,'经典著作'); drop table if exists tb_order; -- 创建订单表 CREATE TABLE tb_order( id INT PRIMARY KEY AUTO_INCREMENT, CODE VARCHAR(32), total DOUBLE, user_id INT, FOREIGN KEY (user_id) REFERENCES tb_user(id) ); -- 插入订单表测试数据 INSERT INTO tb_order(CODE,total,user_id)VALUES('20180315ORDER1212',388.6,1); INSERT INTO tb_order(CODE,total,user_id)VALUES('20180315ORDER1213',217.8,1); drop table if exists tb_item; -- 创建中间表 CREATE TABLE tb_item( order_id INT, article_id INT, amount INT, PRIMARY KEY (order_id,article_id), FOREIGN KEY (order_id) REFERENCES tb_order(id), FOREIGN KEY (article_id) REFERENCES tb_article(id) ); -- 创建插入中间表数据 INSERT INTO tb_item(order_id,article_id,amount)VALUES(1,1,1); INSERT INTO tb_item(order_id,article_id,amount)VALUES(1,2,1); INSERT INTO tb_item(order_id, article_id,amount)VALUES(1,3,2); INSERT INTO tb_item(order_id, article_id,amount)VALUES(2,4,2); INSERT INTO tb_item(order_id…

MyBatis的一对多关联关系
type: item
date: 2018-03-14T05:38:00+00:00
description: 本文修订于2019年3月17日SQL脚本在实际项目开发中，一对多是非常常见的关系，比如，一个班级可以有多个学生，一个学生只能属于一个班级，班级和学生是一对多的关系，而学生和班级是多对一的关系。数据库中一对多关系通常使用主外键关联，外键列应该在多方，即多方维护关系。下面我们就用一个简单示例来看看MyBatis怎么处理一对多关系。首先，给在数据库创建两个表tb_clazz 和tb_student，并插入测试数据。SQL脚本如下:drop table if exists tb_clazz; CREATE TABLE tb_clazz( id INT PRIMARY KEY AUTO_INCREMENT, CODE VARCHAR(18), NAME VARCHAR(18) ); INSERT INTO tb_clazz(CODE,NAME) VALUES('201803','计算机专业'); drop table if exists tb_student; CREATE TABLE tb_student( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(18), sex VARCHAR(18), age INT, clazz_id INT, FOREIGN KEY(clazz_id) REFERENCES tb_clazz(id) ); INSERT INTO tb_student (NAME,sex,age,clazz_id) VALUES('马云','男',23,1) ; INSERT INTO tb_student (NAME,sex,age,clazz_id) VALUES('李飞飞','女',23,1) ; INSERT INTO tb_student (NAME,sex,age,clazz_id) VALUES('马化腾','男',23,1) ; INSERT INTO tb_student (NAME,sex,age,clazz_id) VALUES('柳青','女',23,1) ; 提示:tb_student表的clazz_id作为外键参照tb_clazz表的主键id。实体类在数据库中执行SQL脚本，完成创建数据库和表的操作。接下来，创建一个Clazz对象和一个Student对象分别映射tb_clazz和tb_student表。班级和学生是一对多的关系，即一个班级可以有多个学生。在Clazz类当中定义了一个students属性，该属性是一个List集合，用来映射一对多的关联关系，表示一个班级有多个学生。import java.io.Serializable; import java.util.List; public class Clazz implements Serializable { private static final long serialVersionUID = 1L; private Integer id; // 班级id，主键 private String code; // 班级编号 private String name; // 班级名称 // 班级和学生是一对多的关系，即一个班级可以有多个学生 private List<Student> students; public Clazz() { super(); } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } @Override public String toString() { return "Clazz [id=" + id + ", code=" + code + ", name=" + name + "]"; } } 班级和学生是一对多的关系，即一个班级可以有多个学生。在Clazz类当中定义了一个students属性，该属性…

MyBatis的一对一关联关系
type: item
date: 2018-03-13T06:08:00+00:00
description: 本文修订日期：2019年11月25日SQL脚本在实际项目开发中，经常存在一对一关系，比如一个人只能有一个身份证，一个身份证只能给一个人使用，这就是一对一的关系。一对一关系推荐使用唯一主外键关联，即两张表使用外键关联，由于是一对一关联，因此还需要给外键列增加unique唯一约束。下面我们就用一个简单示例来看看MyBatis怎么处理一对一关系。首先，在数据库创建两个表tb_card和tb_person，并插入测试数据。SQL 脚本如下: drop table if exists tb_card; create table tb_card ( id int primary key auto_increment, code varchar(18) ); insert into tb_card(code) values ('432801198009191038'); drop table if exists tb_person; create table tb_person ( id int primary key auto_increment, name varchar(18), sex varchar(18), age int, card_id int unique, foreign key(card_id) peferences tb_card(id) ); insert into tb_person(name, sex, age, card_id) values ('jack','男',23,1) ; 提示:tb_person表的card_id作为外键，其参照tb_card表的主键id，因为是一对一关系，即一个card只能让一个person使用，所以card_id做成了唯一键约束。如此一来，当一个person使用了一个card之后，其他的person就不能使用该card了。实体类接下来，创建一个Card对象和一个Person对象分别映射tb_card和tb_person表。package cn.mybatis.mydemo.domain; import java.io.Serializable; public class Card implements Serializable { private static final long serialVersionUID = 1L; private Integer id; // 主键id private String code; // 身份证编号 public Card() { super(); } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } @Override public String toString() { return "Card [id=" + id + ", code=" + code + "]"; } } package cn.mybatis.mydemo.domain; import java.io.Serializable; public class Person implements Serializable { private static final long serialVersionUID = 1L; private Integer id; // 主键id private String name; // 姓名 private String sex; // 性别 private Integer age; // 年龄 // 人和身份证是一对一的关系，即一个人只有一个身份证 private Card card; public Person() { super(); } 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 String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Integer getAge(…