Mybatis(下)
Mybatis(下)
一、MaBatis核心配置文件
Mybatis 中文文档
Mybatis 中文文档
1. properties
定义属性及读取属性文件,取的时候用 $(name) ,name 为之前定义的name
定义属性
SqlMappingConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
读取属性文件
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3307/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
SqlMappingConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
读取属性优先级
2. settings
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行。
settings 中的设置名可以查看文档。
这里举个驼峰命名法例子。
不开启驼峰命名法时,数据库里用下划线,domain里也要用下划线。
CREATE TABLE `customer` (
`cust_id` int(11) NOT NULL AUTO_INCREMENT,
`cust_name` varchar(255) DEFAULT NULL,
`cust_profession` varchar(255) DEFAULT NULL,
`cust_phone` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
@Setter@Getter
public class Customer {
private Integer cust_id;
private String cust_name;
private String cust_profession;
private String cust_phone;
private String email;
@Override
public String toString() {
return "Customer{" +
"cust_id=" + cust_id +
", cust_name='" + cust_name + '\'' +
", cust_profession='" + cust_profession + '\'' +
", cust_phone='" + cust_phone + '\'' +
", email='" + email + '\'' +
'}';
}
}
如果数据库里用下划线,domain里用驼峰命名法。不开启驼峰命名法的情况下是取不到值的。
@Setter@Getter
public class Customer {
private Integer custId;
private String custName;
private String custProfession;
private String custPhone;
private String email;
@Override
public String toString() {
return "Customer{" +
"custId=" + custId +
", custName='" + custName + '\'' +
", custProfession='" + custProfession + '\'' +
", custPhone='" + custPhone + '\'' +
", email='" + email + '\'' +
'}';
}
}
@Test
public void test2(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
Customer customerbyId = mapper.getCustomerById(2);
System.out.println(customerbyId);
}
上面代码会输出 Customer{custId=null, custName='null', custProfession='null', custPhone='null', email='libai@163.com'}
开启驼峰命名法之后就能取到值
会输出 Customer{custId=2, custName='李白', custProfession='刺客', custPhone='18977665521', email='libai@163.com'}
3. typeAliases
类型别名是为 Java 类型设置一个短的名字。
定义单个别名
定义别名后,domain.xml中的,resultType 可以由全限定名称改为一个短的别名。
批量别名定义
批量定义包下类的别名,将他们的别名设为类名。定义别名后,domain.xml中的,resultType 可以由全限定名称改为一个短的别名。
注意
如果当前包类与子包类重名,别名相同,会有异常。
这时候可以在类上使用注解 @Alias("别名"),起不同的别名。
4. typeHandlers
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
JDK1.8之后实现全部的JSR310规范,日期时间处理上,我们可以使用MyBatis基于JSR310(Date and Time API)
编写的各种日期时间类型处理器。
MyBatis3.4以前的版本需要我们手动注册这些处理器,以后的版本都是自动注册的。
5. Plugins
插件是MyBatis提供的一个非常强大的机制,MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。
通过插件来修改MyBatis的一些核心行为。
6. Environments
MyBatis可以配置多种环境,比如开发、测试和生产环境需要有不同的配置。
每种环境使用一个environment标签进行配置并指定唯一标识符,可以通过environments标签中的default属性指定一个环境的标识符来快速的切换环境
Environment子标签
(1)transactionManager 事务管理
type有以下取值:
① JDBC :使用JDBC 的提交和回滚设置,依赖于从数据源得到的连接来管理事务范围
② MANAGED :不提交或回滚一个连接、让容器来管理事务的整个生命周期;ManagedTransactionFactory
③ 自定义 :实现TransactionFactory接口 ;type=全类名/别名
(2)dataSource 数据源
type有以下取值:
① UNPOOLED :不使用连接池UnpooledDataSourceFactory
② POOLED :使用连接池PooledDataSourceFactory
③ JNDI :在EJB 或应用服务器这类容器中查找指定的数据源
④ 自定义 : 实现DataSourceFactory接口,定义数据源的获取方式
实际开发
实际开发中我们使用Spring管理数据源,并进行事务控制的配置来覆盖上述配置
7. databaseIDProvider
MyBatis 可以根据不同的数据库厂商执行不同的语句。
可以能过databaseIDProvider标签来进行设置。
databaseId 选择数据库厂商
8. mappers
(1)
使用相对于类路径的资源。
(2)
使用mapper接口类路径。此种方法要求:
① mapper接口名称和mapper映射文件名称相同
② mapper接口和mapper映射文件放在同一个目录中(同包下)
(3)指定包下的所有mapper接口。此种方法要求:
① mapper接口名称和mapper映射文件名称相同
② mapper接口和mapper映射文件放在同一个目录中(同包下)
二、输出类型
1. 输出简单类型
2. Map
(1)第一种形式
key:是列名,value:是列名对应的值
CustomerMapper
public interface CustomerMapper {
Integer getCount();
Map getbyId(Integer id);
}
CustomerMapper.xml
Test
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
Map map = mapper.getbyId(1);
System.out.println(map);
sqlSession.close();
}
output(key:是列名,value:是列名对应的值)
{cust_profession=射手, cust_name=鲁班, cust_id=1, cust_phone=13499887733, email=12341241@qq.com}
(2)第二种形式
Map
CustomerMapper
public interface CustomerMapper {
Integer getCount();
Map getbyId(Integer id);
@MapKey("cust_id")
Map getAll();
}
CustomerMapper.xml
Test
@Test
public void test() {
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
Map map = mapper.getAll();
for (Integer integer : map.keySet()) {
System.out.println("Key:" + integer + "; Value:" + map.get(integer));
}
sqlSession.close();
}
output(key为自己指定的列:@MapKey("cust_id"))
Key:1; Value:{cust_profession=射手, cust_name=鲁班, cust_id=1, cust_phone=13499887733, email=12341241@qq.com}
Key:2; Value:{cust_profession=刺客, cust_name=李白, cust_id=2, cust_phone=18977665521, email=libai@163.com}
Key:3; Value:{cust_profession=刺客, cust_name=阿轲, cust_id=3, cust_phone=18977665997, email=aike@qq.com}
Key:4; Value:{cust_profession=肉盾, cust_name=德玛西亚, cust_id=4, cust_phone=13700997665, email=demaxiya.126.com6}
Key:5; Value:{cust_profession=战士, cust_name=李信, cust_id=5, cust_phone=13586878987, email=yasuo@qq.com}
Key:6; Value:{cust_profession=辅助, cust_name=奶妈, cust_id=6, cust_phone=13398909089, email=nama@qq.com}
…………
3. resultMap
之有在写输出时使用的都是resultType,但是resultType要求必须得要字段名称和数据库当中的名称一致时才能有值,否则为null。
Customer
@Setter@Getter@ToString
public class Customer {
private Integer cust_id;
private String cust_name;
private String cust_profession;
private String cust_phone;
private String email;
}
CustomerMapper
public interface CustomerMapper {
Integer getCount();
Customer getbyId(Integer id);
List getAll();
}
CustomerMapper.xml
Test
@Test
public void testOne() {
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
Customer customer = mapper.getbyId(2);
System.out.println(customer);
sqlSession.close();
}
@Test
public void testAll() {
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
List list = mapper.getAll();
for (Customer customer : list) {
System.out.println(customer);
}
sqlSession.close();
}
如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系。
Customer
@Setter@Getter@ToString
public class Customer {
private Integer id;
private String name;
private String profession;
private String phone;
private String email;
}
CustomerMapper
public interface CustomerMapper {
Integer getCount();
Customer getbyId(Integer id);
List getAll();
}
CustomerMapper.xml
Test
@Test
public void testOne() {
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
Customer customer = mapper.getbyId(2);
System.out.println(customer);
sqlSession.close();
}
@Test
public void testAll() {
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
List list = mapper.getAll();
for (Customer customer : list) {
System.out.println(customer);
}
sqlSession.close();
}
三、多表操作
1. 表之间关系
(1)一对一
一夫一妻
(2)一对多
一个部门有多个员工,一个员工只能属于某一个部门。
一个班级有多个学生,一个学生只能属于某一个班级。
一个客户有多个订单,一个订单只能属于某一个客户。
(3)多对多
一个老师教多个学生,一个学生可以被多个老师教。
一个学生可以先择多门课程,一门课程可以被多个学生选择。
一个用户可以选择多个角色,一个角色也可以被多个用户选择。
2. 表之间关系建表原则
(1)一对多
在多的一方创建一个外键,指向的一方的主键
(2)多对多
创建一个中间表,中间表至少有两个字段,分别作为外键指向多对多双方的主键
3. ManyToOne 多对一
一个客户有多个订单,一个订单只能属于某一个客户。
order 订单表
-- ----------------------------
-- Table structure for order
-- ----------------------------
DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (
`order_id` int(11) NOT NULL AUTO_INCREMENT,
`order_name` varchar(255) DEFAULT NULL,
`order_num` varchar(20) DEFAULT NULL,
`cust_id` int(11) DEFAULT NULL,
PRIMARY KEY (`order_id`),
KEY `fk_order` (`cust_id`),
CONSTRAINT `fk_order` FOREIGN KEY (`cust_id`) REFERENCES `customer` (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of order
-- ----------------------------
INSERT INTO `order` VALUES ('1', '订单名称1', '10001', '2');
INSERT INTO `order` VALUES ('2', '订单名称2', '10002', '3');
INSERT INTO `order` VALUES ('3', '订单名称3', '10003', '2');
INSERT INTO `order` VALUES ('4', '订单名称4', '10004', '4');
(1)查询
Ⅰ)左连接查询
查询所有的订单及订单所对应的客户。
左连接:把左边表的数据全部查出,右边表只查出满足条件的记录。
sql:
SELECT * FROM `order` AS o LEFT JOIN customer AS c ON o.cust_id = c.cust_id
① 建立domain
Customer
@Setter@Getter@ToString
public class Customer {
private Integer cust_id;
private String cust_name;
private String cust_profession;
private String cust_phone;
private String email;
}
Order
@Setter@Getter@ToString
public class Order {
private Integer order_id;
private String order_name;
private String order_num;
private Customer customer;
}
② 建立Mapping映射
OrderMapper
public interface OrderMapper {
/*查询所有的订单*/
public List getAllOrders();
}
OrderMapper.xml
(a)不使用 association,同名的列(property和column相同)可以省略
<?xml version="1.0" encoding="UTF-8" ?>
省略后:
<?xml version="1.0" encoding="UTF-8" ?>
(b)使用 association(推荐,可以用分布查询),都不能省略
<?xml version="1.0" encoding="UTF-8" ?>
③ 测试类
Test
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.openSession();
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
List list = mapper.getAllOrders();
for (Order order : list) {
System.out.println(order);
}
sqlSession.close();
}
Ⅱ)分步查询
① 第一步 先查出所有的订单
OrderMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
② 第二步 根据id查出对应客户
CustomerMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
③ 测试类
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.openSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
Order order = orderMapper.getOrderbyId(1);
System.out.println(order);
sqlSession.close();
}
Ⅲ )分部查询懒加载
(2)添加
先添加客户,获取客户生成的id,再去添加订单
① 添加客户
public interface CustomerMapper {
Integer getCount();
Customer getbyId(Integer id);
List getAll();
/* 保存客户 */
public void insertCustomer(Customer customer);
}
CustomerMapper.xml
insert into `customer`(cust_name,cust_profession,cust_phone,email)
values (#{cust_name},#{cust_profession},#{cust_phone},#{email})
② 添加订单
public interface OrderMapper {
/*查询所有的订单*/
public List getAllOrders();
/*根据id查询订单*/
public Order getOrderbyId(Integer id);
/*保存订单*/
public void insertOrder(Order order);
}
OrderMapper.xml
insert into `order`(order_name,order_num,cust_id)
values (#{order_name},#{order_num},#{customer.cust_id})
③ 测试
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
Order order = new Order();
order.setOrder_name("新订单001");
order.setOrder_num("20000001001");
Customer customer = new Customer();
customer.setCust_name("新客户001");
customer.setCust_phone("137090909090");
customer.setEmail("123123@163.com");
customer.setCust_profession("新职业001");
/* 设置关系 */
order.setCustomer(customer);
/* 先添加客户 获取客户生成的id 再去添加订单*/
customerMapper.insertCustomer(customer);
System.out.println(customer);
/* 保存订单 */
orderMapper.insertOrder(order);
sqlSession.commit();
sqlSession.close();
}
4. OnToMany 一对多
(1)查询
Ⅰ)左连接查询
Customer
@Setter@Getter@ToString
public class Customer {
private Integer cust_id;
private String cust_name;
private String cust_profession;
private String cust_phone;
private String email;
private List orders = new ArrayList<>();
}
CustomerMapper
public interface CustomerMapper {
Integer getCount();
Customer getbyId(Integer id);
/*保存客户*/
void insertCustomer(Customer customer);
/*查询所有客户*/
List getAllCustomers();
}
CustomerMapper.xml
测试
@Test
public void test4(){
/*查询所有客户*/
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
List allCustomers = customerMapper.getAllCustomers();
for (Customer allCustomer : allCustomers) {
System.out.println(allCustomer);
}
sqlSession.close();
}
Ⅱ)分步查询
CustomerMapper.xml
OrderMapper
public interface OrderMapper {
/*查询所有的订单*/
List getAllOrders();
/*根据id查询订单*/
Order getOrderbyId(Integer id);
/*保存订单*/
void insertOrder(Order order);
/*根据cust_id查询订单*/
Order getOrderbyCustId(Integer id);
}
OrderMapper.xml
测试和 左连接查询一样。
(2)添加
CustomerMapper.xml
insert into `customer`(cust_name,cust_profession,cust_phone,email)
values (#{cust_name},#{cust_profession},#{cust_phone},#{email})
OrderMapper
public interface OrderMapper {
/*查询所有的订单*/
List getAllOrders();
/*根据id查询订单*/
Order getOrderbyId(Integer id);
/*保存订单*/
void insertOrder(Order order);
/*根据cust_id查询订单*/
Order getOrderbyCustId(Integer id);
/*更新与客户的关系*/
void updateCustId(@Param("orderId") Integer orderId, @Param("custId") Integer custId);
}
CustomerMapper.xml
INSERT INTO `order` (order_name, order_num, cust_id)
VALUES (#{order_name}, #{order_num}, #{customer.cust_id})
UPDATE `order` SET `cust_id` = #{custId} WHERE `order_id` = #{orderId}
测试
@Test
public void test5(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
Customer customer = new Customer();
customer.setCust_name("新客户");
Order order1 = new Order();
order1.setOrder_name("订单2");
Order order2 = new Order();
order2.setOrder_name("订单2");
customer.getOrders().add(order1);
customer.getOrders().add(order2);
/*保存数据*/
customerMapper.insertCustomer(customer);
orderMapper.insertOrder(order1);
orderMapper.insertOrder(order2);
/*更新关系*/
for (Order order : customer.getOrders()) {
orderMapper.updateCustId(order.getOrder_id(),customer.getCust_id());
}
sqlSession.commit();
sqlSession.close();
}
(3)删除
删除时一定要先打破关系再做删除操作
CustomerMapper
public interface CustomerMapper {
Integer getCount();
Customer getbyId(Integer id);
/*保存客户*/
void insertCustomer(Customer customer);
/*查询所有客户*/
List getAllCustomers();
/*根据id删除客户*/
public void deleteCustomer(Integer id);
}
CustomerMapper.xml
DELETE FROM `customer` WHERE cust_id = #{id}
OrderMapper
public interface OrderMapper {
/*查询所有的订单*/
List getAllOrders();
/*根据id查询订单*/
Order getOrderbyId(Integer id);
/*保存订单*/
void insertOrder(Order order);
/*根据cust_id查询订单*/
Order getOrderbyCustId(Integer id);
/*更新与客户的关系*/
void updateCustId(@Param("orderId") Integer orderId, @Param("custId") Integer custId);
/*打破跟客户关系*/
void updateRelation(Integer custId);
}
OrderMapper.xml
UPDATE `order` SET cust_id = NULL WHERE cust_id = #{custId}
测试
@Test
public void test6(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
// 一对多删除之前 要先打破关系
orderMapper.updateRelation(17);
/*删除客户*/
customerMapper.deleteCustomer(17);
sqlSession.commit();
sqlSession.close();
}
5. ManyToMany 多对多
一个老师教多个学生,一个学生可以被多个老师教。
(0)建表和建实体类
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- 学生表
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`stu_id` int(11) NOT NULL AUTO_INCREMENT,
`stu_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`stu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', '学生1');
INSERT INTO `student` VALUES ('2', '学生2');
INSERT INTO `student` VALUES ('3', '学生3');
INSERT INTO `student` VALUES ('4', '学生4');
INSERT INTO `student` VALUES ('5', '学生5');
-- ----------------------------
-- 老师表
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
`teacher_id` int(11) NOT NULL AUTO_INCREMENT,
`teacher_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`teacher_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of teacher
-- ----------------------------
INSERT INTO `teacher` VALUES ('1', '高老师');
INSERT INTO `teacher` VALUES ('2', '叶老师');
INSERT INTO `teacher` VALUES ('3', '王老师');
-- ----------------------------
-- 学生老师关系表
-- ----------------------------
DROP TABLE IF EXISTS `stu_teacher_rel`;
CREATE TABLE `stu_teacher_rel` (
`stu_id` int(11) NOT NULL,
`teacher_id` int(11) NOT NULL,
PRIMARY KEY (`stu_id`,`teacher_id`),
KEY `fk_teacher_rel` (`teacher_id`),
CONSTRAINT `fk_stu_rel` FOREIGN KEY (`stu_id`) REFERENCES `student` (`stu_id`),
CONSTRAINT `fk_teacher_rel` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`teacher_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of stu_teacher_rel
-- ----------------------------
INSERT INTO `stu_teacher_rel` VALUES ('1', '1');
INSERT INTO `stu_teacher_rel` VALUES ('2', '1');
INSERT INTO `stu_teacher_rel` VALUES ('1', '2');
INSERT INTO `stu_teacher_rel` VALUES ('3', '2');
INSERT INTO `stu_teacher_rel` VALUES ('4', '2');
INSERT INTO `stu_teacher_rel` VALUES ('5', '3');
Student
@Setter@Getter @ToString
public class Student {
private Integer stu_id;
private String stu_name;
}
Teacher
@Setter@Getter@ToString
public class Teacher {
private Integer teacher_id;
private String teacher_name;
}
(1)查询
Ⅰ)左连接查询
Teacher
@Setter@Getter@ToString
public class Teacher {
private Integer teacher_id;
private String teacher_name;
private List students = new ArrayList<>();
}
TeacherMapper
public interface TeacherMapper {
/*查询老师 并且把关联的学生也查出来*/
public List getAllTeachers();
}
TeacherMapper.xml
测试
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.openSession();
TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
List allTeachers = teacherMapper.getAllTeachers();
for (Teacher teacher : allTeachers) {
System.out.println(teacher);
}
sqlSession.close();
}
Ⅱ)分步查询
TeacherMapper
public interface TeacherMapper {
/*查询老师 并且把关联的学生也查出来*/
public List getAllTeachers();
/*查询指定的老师*/
public Teacher getTeacherWithId(Integer id);
}
TeacherMapper.xml
StudentMapper
public interface StudentMapper {
/*根据老师id查询学生*/
public List getStuByTeach(Integer id);
}
StudentMapper.xml
测试
@Test
public void test2(){
SqlSession sqlSession = MybatisUtils.openSession();
TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = teacherMapper.getTeacherWithId(2);
System.out.println(teacher);
sqlSession.close();
}
(2)添加
添加老师,添加学生,添加中间关系
TeacherMapper
public interface TeacherMapper {
/*查询老师 并且把关联的学生也查出来*/
public List getAllTeachers();
/*查询指定的老师*/
public Teacher getTeacherWithId(Integer id);
/*保存老师*/
void insertTeacher(Teacher teacher);
/*插入关系表*/
void insertRelation(@Param("stuId") Integer stuId, @Param("teacherId") Integer teacherId);
}
TeacherMapper.xml
INSERT INTO `teacher` (teacher_name) VALUES (#{teacher_name})
INSERT INTO stu_teacher_rel (stu_id, teacher_id) VALUES (#{stuId}, #{teacherId})
StudentMapper
public interface StudentMapper {
/*根据老师id查询学生*/
public List getStuByTeach(Integer id);
/*保存学生*/
void insertStudent(Student student1);
}
StudentMapper.xml
INSERT INTO `student` (stu_name) VALUES (#{stu_name})
测试
@Test
public void test3(){
SqlSession sqlSession = MybatisUtils.openSession();
TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Teacher teacher = new Teacher();
teacher.setTeacher_name("新老师");
Student student1 = new Student();
student1.setStu_name("新学生2");
Student student2 = new Student();
student2.setStu_name("新学生2");
teacher.getStudents().add(student1);
teacher.getStudents().add(student2);
/*保存老师*/
teacherMapper.insertTeacher(teacher);
/*保存学生*/
studentMapper.insertStudent(student1);
studentMapper.insertStudent(student2);
/*插入关系表*/
for (Student student : teacher.getStudents()) {
teacherMapper.insertRelation(student.getStu_id(),teacher.getTeacher_id());
}
sqlSession.commit();
sqlSession.close();
}
四、动态sql
1. 什么是动态sql
通过mybatis提供的各种标签方法实现动态拼接sql。
2. if 标签
需求:根据客户名称和职业来查询客户
public interface CustomerMapper {
/*根据客户名称和职业来查询*/
List getCustomer (@Param("name") String name, @Param("profession") String profession);
}
CustomerMapper.xml
测试
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
List customers = customerMapper.getCustomer("李白","刺客");
for (Customer customer : customers) {
System.out.println(customer);
}
sqlSession.close();
}
原始查询存在问题
有可能传入的名称或职业为空,那时就找不到记录了,可以使用 if 标签来进行判断。
CustomerMapper.xml
这样,能够解决:
① List
Preparing: SELECT * FROM customer WHERE cust_name = ? AND cust_profession = ?
Parameters: 李白(String), 刺客(String)
② List
Preparing: SELECT * FROM customer WHERE cust_name = ?
Parameters: 李白(String)
存在的问题
① List
Preparing: SELECT * FROM customer WHERE AND cust_profession = ?
Parameters: 刺客(String)
如果第一个条件为null,后面就会多一个and执行就会报错
② List
Preparing: SELECT * FROM customer WHERE
如果所有条件为null,后面就会多一个WHERE执行就会报错
3. Where 标签
解决 if 标签留下的两个问题
① 会自动去掉 where 后面第一个前And
② 如果没有条件就不会加 where
4. trim 标签
① prefix:设置前缀,在第一个条件之前加一个前缀。
② prefixOverrides:前缀条件覆盖,把第一个条件之前的值覆盖(变成空)
③ suffix:设置后缀,在最后一个条件之后加一个后缀。
④ suffixOverrides::后缀条件覆盖,把最后一个条件之后的值覆盖(变成空)
5. choose 标签
① choose:选择一个条件,只要第一个条件满足,后面条件都不执行
② when:写条件
③ otherwise:除此以外
6. set 标签
① 会自动去掉最后一个设置的逗号
② 会添加update语句中 set
CustomerMapper
public interface CustomerMapper {
/*根基客户名称和职业来查询*/
List getCustomer (@Param("name") String name, @Param("profession") String profession);
/*更新客户*/
public void updateCustomer(Customer customer);
}
CustomerMapper.xml
update `customer`
cust_name=#{cust_name},
cust_profession=#{cust_profession},
where cust_id = #{cust_id}
测试
@Test
public void test2(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
Customer customer = new Customer();
customer.setCust_id(2);
customer.setCust_name("李白白");
customer.setCust_profession("战士");
customerMapper.updateCustomer(customer);
sqlSession.commit();
sqlSession.close();
}
7. foreach 标签
查询条件值为指定的值当中
public interface CustomerMapper {
/*根据id查询指定的客户 多个客户*/
List getCustomers();
}
CustomerMapper.xml
测试
@Test
public void test3(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
List customers = customerMapper.getCustomers();
for (Customer customer : customers) {
System.out.println(customer);
}
sqlSession.close();
}
给定的值可以以三种形式给出
(1)数组
查询条件值为指定的值当中
public interface CustomerMapper {
/*根据id查询指定的客户 多个客户*/
List getCustomers(Integer[] ids);
}
CustomerMapper.xml
测试
@Test
public void test3(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
List customers = customerMapper.getCustomers(new Integer[]{2,3,4,5});
for (Customer customer : customers) {
System.out.println(customer);
}
sqlSession.close();
}
(2)List
查询条件值为指定的值当中
public interface CustomerMapper {
/*根据id查询指定的客户 多个客户*/
List getCustomers(List ids);
}
CustomerMapper.xml
测试
@Test
public void test3(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
ArrayList arrayList = new ArrayList<>();
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
arrayList.add(6);
List customers = customerMapper.getCustomers(arrayList);
for (Customer customer : customers) {
System.out.println(customer);
}
sqlSession.close();
}
(3)VO
创建 VO (VO = Value Object 数据包装类)
@Setter@Getter
public class QueryVo {
private Integer[] ids;
private List idList;
}
CustomerMapper
public interface CustomerMapper {
/*根据id查询指定的客户 多个客户*/
List getCustomers(QueryVo queryVo);
}
CustomerMapper.xml(第一种)
CustomerMapper.xml(第二种)
测试(第一种)
@Test
public void test3(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
QueryVo queryVo = new QueryVo();
queryVo.setIds(new Integer[]{2,3,4,5});
List customers = customerMapper.getCustomers(queryVo);
for (Customer customer : customers) {
System.out.println(customer);
}
sqlSession.close();
}
测试(第二种)
@Test
public void test3(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
QueryVo queryVo = new QueryVo();
ArrayList arrayList = new ArrayList<>();
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
arrayList.add(6);
queryVo.setIdList(arrayList);
List customers = customerMapper.getCustomers(queryVo);
for (Customer customer : customers) {
System.out.println(customer);
}
sqlSession.close();
}
8. bind 标签
bind标签:声明一个变量,绑定值;可以取出传入的值,重新处理,赋值给别外一个值
public interface CustomerMapper {
Customer getCustomerbyId(@Param("id") Integer id);
}
① 声明一个变量,绑定值
CustomerMapper.xml
测试
@Test
public void test4(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
Customer customer = customerMapper.getCustomerbyId(3);
System.out.println(customer);
sqlSession.close();
}
之后查询结果是查id为6的记录。即查询的参数是以bind标签绑定的数据为准。
② 可以取出传入的值,重新处理,赋值给别外一个值
CustomerMapper.xml
测试同上,查询结果是查id为5的记录。
9. Sql 片段
Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。
sql 片段中还能使用动态标签
select cust_name from `customer`
select * from `customer`
include 中还能添加属性
select cust_profession from `customer`
select cust_name from `customer`
select * from `customer`
五、缓存
1. 缓存介绍
MyBatis中使用缓存来提高其性能。当查询数据时,会先从缓存中取出数据,如果缓存中没有,再到数据库当中查询。
MyBatis中的缓存分为两种:一级缓存和二级缓存,一级缓存是sqlSession级别的,二级缓存是mapper级别的。
2. 一级缓存
(1)一级缓存
本地缓存 (默认开启),在sqlSession没有关闭之前,再去查询时,会从缓存当中取出数据,不会重新发送新的sql。
(2)一级缓存失效
① 如果在查询之前,执行了增/删/改操作,缓存就会失效。
② 手动清空缓存 :sqlSession.clearCache();
③ 如果两次的查询条件不一样,缓存也会失效。
④ 如果两个查询在不同的sqlsession当中。
3. 二级缓存
(1)二级缓存介绍
全局作用域缓存,一个namespace对应一个缓存。
如果会话关闭,一级缓存的数据会被保存到二级缓存中。
不同namespace查出的数据,会放到自己对应的缓存中,现在默认也是打开的。
(2)二级缓存使用步骤
Ⅰ)确保在配置文件当中开启二级缓存
Ⅱ)在对应的mapper中添加cache标签
cache标签的属性:
① eviction:回收策略
? a)LRU (默认):最近最少使用,移除最长时间不使用的对象。
? b)FIFO :先进先出,按对象进入缓存的顺序移除对象。
? c)SOFT :软引用,移除基本垃圾回收器状态和软引用规则的对象。
? 没有对象引用了,但是空间足够,暂时不回收。
? d)WEAK :弱引用,移除基本垃圾回收器状态和弱引用规则的对象。
? 当没有对象引用了,立即回收。
② flushInterval
刷新间隔,单位毫秒,默认情况下是不设置,没有刷新间隔缓存调用语句时刷新。
③ readOnly :是否只读
? a)true :告诉Mybatis是只读操作,不去修改数据
? Mybatis为了加快获取速度,会直接将缓存的引用将给用,不安全,,速度快。
? b)false :非只读,有可能修改数据
? Mybatis会利用序列化和反序列化复制一份给你,安全,速度慢。
④ size :可以存放多少个元素
⑤ type :可以用来指定自定义的缓存,可以使用Mybatis自己的缓存,也可以使用第三方的缓存。
Ⅲ )POJO需要实现Serializable接口
@Setter@Getter@ToString
public class Customer implements Serializable {
private Integer cust_id;
private String cust_name;
private String cust_profession;
private String cust_phone;
private String email;
}
(3)注意事项
查询的数据都会先放到一级缓存当中,只有会话关闭,一级缓存中的数据才会转称到二级缓存中。
(4)缓存相关属性
① cacheEnabled:只能控制二级缓存的开关
② select标签中useCache:控制的也是二级缓存是否使用,默认是true
③ 增删改标签中flushCache
设置为true, 语句被调用,一级和二级都会被清空。
增删改flushCache默认为true;查询flushCache默认为false
④ sqlSession.clearCache() :只清除当前session的一级缓存
⑤ localCacheScope :本地缓存作用域
取值:SESSION 和 STATEMENT,默认是 SESSION
可以使用STATEMENT,禁用缓存
4. 缓存使用顺序
先到二级缓存当中查找;如果二级缓存中没有,就去找一级缓存;如果一级缓存中也没有,就去到数据库当中查询。
六、逆向工程(代码生成器)
MyBatis Generator
代码生成器,可以根据指定的表快速生成对应的映射文件,接口,以及Bean类。
支持基本的增删改查,以及QBC风格的条件查询,但是一些复杂的表连接还是需要我们自己来去编写。
使用
1. 下载
下载地址
2. 把相关jar导入到工程当中
3. 创建generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
4. 编写生成代码
public void test() throws Exception {
List warnings = new ArrayList();
boolean overwrite = true;
File configFile = new File("./resource/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
5. 测试
@Test
public void test2(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
List customers = customerMapper.selectAll();
for (Customer customer : customers) {
System.out.println(customer);
}
sqlSession.close();
}
七、分页插件
1. 下载分页插件
下载地址
- jsqlparser-2.0.jar
- pagehelper-5.1.10.jar
2. 配置分页插件
SqlMappingConfig.xml
3. 使用分页插件
@Test
public void test2(){
SqlSession sqlSession = MybatisUtils.openSession();
CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
Page