目录
一、MyBatis
1.概述
2.JavaEE三层架构简单介绍
(1)表现层
(2)业务层
(3)持久层
3.框架
4.优势
(1)JDBC的劣势
(2)MyBatis优化
5.使用
(1)快速上手
(2)框架使用部分
(3)编码部分
6.Mapper代理开发
(1)Mapper代理开发的好处
(2)Mapper代理使用步骤
7.Mybatis的配置文件说明
8.查询过程出现的问题
9.xml文件中编写SQL语句没有提示
10.查操作
(1)单条件查询
(2)多条件查询
11.动态查询
(1)多条件动态查询
(2)单条件动态查询(多选一)
12.增操作
(1)主键返回
13.删操作
14.改操作
(1)修改字段数据
(2)修改动态字段数据
15.删操作
(1)单个删除
(2)批量删除
16.Mybatis参数传递
(1)单个参数
(2)多个参数
17.注解方式完成增删改查
MyBatis 是一款优秀的持久层框架,用于简化JDBC 开发
MyBatis 本是Apache 的一个开源项目iBatis,2010年这个项目由apache softwarefoundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github
网址:mybatis – MyBatis 3 | 简介
辅助插件:MybatisX
页面展示
逻辑处理
负责将数据到保存到数据库的那一层代码
框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型
在框架的基础之上构建软件编写更加高效、规范、通用、可扩展
硬编码
注册驱动,获取连接
SQL语句
操作较繁琐
手动设置参数
手动封装结果集
MyBatis 免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作
框架使用部分:
创建模块,导入坐标
编写核心配置文件
编写SQL映射文件
编码部分:
定义实体类(POJO类)
加载核心配置文件,获取SqlSessionFactory对象
获取SqlSession对象
释放资源
导入坐标
org.mybatis
mybatis
3.5.9
mysql
mysql-connector-java
5.1.46
junit
junit
4.13
test
org.slf4j
slf4j-api
1.7.20
ch.qos.logback
logback-classic
1.2.3
ch.qos.logback
logback-core
1.2.3
核心配置文件,文件名通常:mybatis-config.xml
编写SQL映射文件,名称:要操作的表名+Mapper(ProductMapper.xml)
如果映射文件SQL语句中表名爆红,只是警告,并不影响实际操作
产生原因:ldea和数据库没有建立连接,不识别表信息
解决方法:用IDEA与数据库建立连接即可
定义实体类
要与数据库中的数据类型对应
使用
public class MybatisDemo {
public static void main(String[] args) throws IOException {
// 1.加载核心配置文件,直接从官网粘过来就行了,获取SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.获取sqlSession对象
final SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.执行SQL
final List list = sqlSession.selectList("product.selectAll");
System.out.println(list);
// 4.释放资源
sqlSession.close();
}
}
解决原生方式中的硬编码(更安全)
简化后期执行SQL
定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下
检查方式:编译项目
在文件夹中打开
如下图即为成功
设置SQL映射文件的namespace属性为Mapper接口全限定名
在Mapper 接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致
【如果Mapper接口名称和SQL映射文件名称相同,并且在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载,如下图】
编码
通过 SqlSession的 getMapper方法获取 Mapper接口的代理对象
调用对应方法完成sql的执行
// 3.执行SQL
// 3-1.获取接口的代理对象
final ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
final List products = mapper.selectAll();
products.forEach(product -> System.out.println(product));
可访问网址查看,后续再补
如以下情况
原因:实体类属性名称与数据库字段名称不一致,导致不能自动封装数据
解决方法一:
为数据库字段起别名,让其和实体类属性名称一致(麻烦,不推荐)
方法一的优化方案:
写一个SQL语句块,不灵活,还是不推荐~
解决方法二:
结果映射,resultMap【有两个子标签,一个result,一个id,其中id子标签用来完成主键字段的映射,result用来映射普通字段的映射,使用方法与result一致】
type支持别名
再次运行
在xml文件中按alt+enter
往下拉,根据安装的数据库选择合适的即可
Mybatis提供了三种方式:
mapper.xml:
pojo实体类:
public class Employee {
private Integer empNo;
private Date birthDate;
private String firstName;
private String lastName;
private Character gender;
private Date hireDate;
public Employee() {
}
public Employee(Integer empNo, Character gender) {
this.empNo = empNo;
this.gender = gender;
}
public Employee(Integer empNo, Date birthDate, String firstName, String lastName, Character gender, Date hireDate) {
this.empNo = empNo;
this.birthDate = birthDate;
this.firstName = firstName;
this.lastName = lastName;
this.gender = gender;
this.hireDate = hireDate;
}
public Integer getEmpNo() {
return empNo;
}
public void setEmpNo(Integer empNo) {
this.empNo = empNo;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Character getGender() {
return gender;
}
public void setGender(Character gender) {
this.gender = gender;
}
public Date getHireDate() {
return hireDate;
}
public void setHireDate(Date hireDate) {
this.hireDate = hireDate;
}
@Override
public String toString() {
return "Employee{" +
"empNo=" + empNo +
", birthDate=" + birthDate +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", gender=" + gender +
", hireDate=" + hireDate +
'}';
}
}
mapper.EmployeeMapper
/**
* 条件查询01
* 查询员工工号>?且性别为?的所有员工信息
* *参数接收方式
* 1.散装参数:如果方法中有多个参数,需要使用@Param("SQL参数占位符名称”)
* @param empNo 员工工号
* @param character 性别
* @return Employee对象集合
*/
List selectByCondition01(@Param("empNo")int empNo,@Param("gender")Character character);
/**
* 条件查询02:实体类封装参数
* @param employee 员工对象,注意对象的属性名称要和SQL参数占位符名称一致
* @return 员工对象集合
*/
List selectByCondition02(Employee employee);
/**
* 条件查询03:map集合
* @param map map集合,要保证SQL中的参数占位符名称和map集合的键名称一致
* @return 员工对象集合
*/
List selectByCondition03(Map map);
测试:
@Test
public void selectByCondition01() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
final SqlSession sqlSession = sqlSessionFactory.openSession();
final List employees = sqlSession.getMapper(EmployeeMapper.class).selectByCondition01(10001, 'F');
employees.forEach(employee -> System.out.println(employee));
sqlSession.close();
}
@Test
public void selectByCondition022() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
final SqlSession sqlSession = sqlSessionFactory.openSession();
// final List employees = sqlSession.getMapper(EmployeeMapper.class).selectByCondition02(new Employee(10001,'F'));
Employee employee = new Employee();
employee.setEmpNo(10001);
employee.setGender('F');
final List employees = sqlSession.getMapper(EmployeeMapper.class).selectByCondition02(employee);
employees.forEach(e -> System.out.println(e));
sqlSession.close();
}
@Test
public void selectByCondition03() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
final SqlSession sqlSession = sqlSessionFactory.openSession();
Map map = new HashMap();
Integer empNo = 10001;
Character gender = 'F';
map.put("empNo",empNo);
map.put("gender",gender);
final List employees = sqlSession.getMapper(EmployeeMapper.class).selectByCondition03(map);
employees.forEach(e -> System.out.println(e));
sqlSession.close();
}
SQL语句会随着用户的输入或外部条件的变化而变化,我们称为 动态SQL
mybatis对动态SQL用很大的支撑
if:条件判断
test:逻辑判断
choose(when,otherwise)
trim(where,set)
foreach
更具体的可查阅官网,动态SQL
修改一下:
测试时会发现如果没有第一个参数后面会报错
解决方法:
第一种方法:统一格式,第一个条件为一个恒等式
where
# 恒等式
and emp_no > #{empNo}
and gender = #{gender}
第二种方法:使用< where >标签替换where关键字
and emp_no > #{empNo}
and gender = #{gender}
测试:
或者
emp_no > #{empNo}
gender = #{gender}
last_name like #{lastName}
insert into employees
(first_name,last_name,gender,birth_date,hire_date)
VALUES
(#{firstName},#{lastName},#{gender},#{birthDate},#{hireDate})
测试的时候会发现代码运行成功但并没有数据!
打开日志,会发现roll back了
观察日志就会发现 -Setting autocommit to false on JDBC Connection
所以在增操作后,需要使用commit()手动提交一次事务!
再次运行,数据添加成功
如果不想手动提交,可在openSession()传递布尔值以开启是否自动提交
mybatis默认是开启事务的
目的:添加完数据后,获取该数据的id值
insert into employees
(first_name,last_name,gender,birth_date,hire_date)
VALUES
(#{firstName},#{lastName},#{gender},#{birthDate},#{hireDate})
同增
void update(Employee employee);
update employees
set
first_name = #{firstName},
last_name = #{lastName},
gender = #{gender}
where emp_no = #{empNo}
update employees
first_name = #{firstName},
last_name = #{lastName}
where emp_no = #{empNo}
void deleteById(Integer empNo);
delete
from employees
where emp_no = #{empNo}
/**
* 批量删除
* @param empNos id数组
*/
void deleteByIds(@Param("empNos") Integer[] empNos);
delete from employees
where emp_no in
#{empNo}
;
/**
* 批量删除02
* @param empNos id数组
*/
void deleteByIds02(Integer[] empNos);
delete from employees
where emp_no in (
#{empNo}
);
测试
Integer[] integers = {10023,10024,10025,10026,10027,10018,10019,10020,10021,10022};
try {
sqlSession.getMapper(EmployeeMapper.class).deleteByIds(integers);
sqlSession.commit();
} catch (Exception e) {
System.out.println("删除失败");
e.printStackTrace();
}
pojo实体类:直接使用,属性名和参数占位符名称一致即可
Map集合:直接使用,键名和参数占位符名称一致即可
Collection:封装为map
List:封装为map
Array:封装为map
其他:直接使用
会将参数列表封装为map集合,由于默认可读性太差,可以使用@Param替换Map集合中默认的arg键名
map.put(”arg0“,参数值1)
map.put(”param1“ ,参数值1)
map.put(”param2“,参数值2)
map.put(”arg1“,参数值2)
MyBatis提供了 ParamNameResolver 类来进行参数封装
封装方法为getNamedParams
在IDEA中,按住ctrl+shift+a打开action
将 ParamNameResolver粘进搜索框,选择Classes
搜索出来第一个就是,点进去
之后ctrl f。在搜索框输入getNamedParams
使用注解方式会比配置文件开发更加高效
查询:@Select
添加;@Insert
修改:@Update
删除:@Delete
/**
* 根据id查询
* @param empNo id
* @return Employee对象
*/
@Select("select * from employees where emp_no = #{empNo}")
Employee selectById(int empNo);
注意:
注解完成简单功能
配置文件完成复杂功能,(动态SQL)