mybatis笔记
什么是myBatis
mybatis是一个优秀的持久层框架,用于简化JDBC(JDBC白学)
JDBC的缺点
1.硬编码
- 注册驱动和获取链接
- sql语句
2.操作繁琐
- 需要手动封装结果集ResultSet
- preparedstatement手动设置参数
mybatis免除看几乎所有的JDBC代码以及设置参数和获取结果集的工作
myBatis快速入门
创建项目
新建maven模块
在pom.xml中配置mybatis的依赖
1
2
3
4
5<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>x.x.x 为mybatis的版本号
因为项目业务需要,同时也要导入mysql的jar包
1
2
3
4
5<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>配置其他所需要的依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!-- 添加slf4j日志api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>
<!-- 添加logback-classic依赖 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 添加logback-core依赖 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>编写mybatis核心配置文件–>替换连接信息,解决硬编码
mybatis-config.xml文件配置的通用案例(其中部分已经替换)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--加载sql的映射文件-->
<mapper resource="UserMapper.xml"/>
<!--sql的映射文件的取名规则为xxMapper.xml-->
</mappers>
</configuration>创建sql的映射文件
1
2
3
4
5
6
7
8
9<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<select id="selectAll" resultType="com.xgfm.pojo.User">
select * from tb_user;
</select>
</mapper>创建对应的pojo文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61package com.xgfm.pojo;
public class User {
private Integer id;
private String username;
private String password;
private String gender;
private String addr;
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 String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@Override
public String toString() {
return "Tb_user{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", gender='" + gender + '\'' +
", addr='" + addr + '\'' +
'}';
}
}创建mian方法来执行mybatis
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29package com.xgfm;
import com.xgfm.pojo.User;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MybatisDemo {
public static void main(String[] args) throws IOException {
//加载mybatis核心配置文件,获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取sqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
//执行sql语句
List<User> users = sqlSession.selectList("test.selectAll");
System.out.println(users);
//释放资源
sqlSession.close();
}
}
Mapper代理开发
在上述代码中
1 |
|
依旧存在硬编码的问题
为了解决这个问题,便使用mapper进行代理开发
使用Mapper代理开发的步骤
定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下
设置SQL映射文件的namespace属性为Mapper接口全限定名
在Mapper接口中定义方法,方法名就是SQL映射文件sql语句中的id,并保持参数类型和返回值类型一致
进行编码
通过SqlSession的getMapper方法获取Mapper接口的代理对象
1
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
调用代理对象中的对应方法完成sql的执行
1
List<User> users=userMapper.selectAll();
完成!!
附MybatisDemo2
1 |
|
UserMapper接口
1 |
|
UserMapper.xml文件
1 |
|
在mybatis-config.xml文件中
1 |
|
可以对比两种加载映射文件的方法
- mapper标签是一个一个xml进行加载,而package是一整个包进行扫描读取然后进行加载
MyBatis的核心配置文件
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息
environments(环境配置)
- 在其中可以配置多个数据库,动态的切换数据源
配置数据库连接环境信息,可以配置多个environment,通过default属性切换不同的environment
- transactionManager是事务管理标签,type一般是JDBC,基本上不需要修改
- dataSource数据库连接池,一般是POOLED连接池使用
- dataSource中间配置的是property,是数据源配置的基本参数
typeAliases(类型别名配置)
可以为java类型设置一个缩写的名字,仅仅用于XML配置,意在降低冗余的全限定类名书写
例如
1
2
3<typeAliases>
<package name="com.xgfm.pojo"/>
</typeAliases>在mybatis-config.xml文件中配置后,在各个mapper文件中的com.xgfm.pojo.xxx都可以用xxx代替,并且这个xxx是不区分大小写的
例如
1
2
3
4
5
6
7
8
9<select id="selectAll" resultType="User">
select * from tb_user;
</select>
<!--修改前的xml是这样的-->
<select id="selectAll" resultType="com.xgfm.pojo.User">
select * from tb_user;
</select>
mybatis-config.xml文件的配置是有约束的
其中标签的顺序一定要按照这样的顺序
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- environment(环境变量)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
配置文档的顺序必须严格按照这个顺序否则将会报错
增删改查练习(练学)
准备环境
数据库表tb_brand
实体类Brand
测试用例
安装MyBatisX插件
myBatisX是为了效率而生的
查询
练习-查询所有数据
- 编写接口方法
- 结果:List
- 编写SQL语句
- 执行方法,测试
查询所有数据时候会发现输出以下数据
1
Brand{id=1, brandName='null', companyName='null', ordered=5, description='好吃不上火', status=0}
会发现companyName,brandName输出的是null
取别名
数据库表的字段名称和实体类属性名称不一致,不能自动封装,这时候就要在mapper.xml文件改写sql语句,给查询的字段取别名
- 缺点:很不方便
1
2
3
4<select id="selectAll" resultType="com.xgfm.pojo.Brand">
select id, brand_name as brandName , company_name as companyName,ordered,description,status
from tb_brand;
</select>然后在查询中就可以找到这些数据了
但是如果以后要用很多查询的时候每次都要起别名是很麻烦的
sql片段
可以在外面定义Sql片段
1
2
3
4
5
6
7
8<sql id="brand_column">
id, brand_name as brandName , company_name as companyName,ordered,description,status
</sql>
<select id="selectAll" resultType="brand">
select <include refid="brand_column"/>
from tb_brand;
</select>但是这样写,也不灵活
使用resultMap
- resultMap定义resultMap
- 在select标签使用resultMap属性替换resultType属性(resultType的原来的type在resultMap中的type字段好像是一致的)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<resultMap id="brandResultMap" type="brand">
<!--
id:完成主键字段的映射
column:表的列名
property:实体类的属性名
result:完成一般字段的映射
column:表的列名
property:实体类的属性名
-->
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<select id="selectAll" resultMap="brandResultMap">
select *
from tb_brand;
</select>这样代替更加灵活,方便更改
练习-查询-查看详情
- 编写接口方法
- 参数:id
- 结果:Brand
- 编写SQL语句
- 执行方法,进行测试
- 编写接口方法
参数占位符:
#{}
会将其替换为? 为了防止SQL注入进行使用
${}
直接拼SQL,会存在SQL注入问题
所以参数传递的时候都使用#{}
而${}一般使用在表名或者列名不固定的情况,但也并不是很常用
参数类型设置:parameterType,大多时候可以省略
特殊字符的处理:
因为sql是写在mapper.xml文件中的,如果在sql语句中使用<等类似的有占用情况的特殊字符,会报错,这时候有以下几种解决方法:
转义字符
网上搜索对应的转义字符结果即可
CDATA区
1
2
3<![CDATA[
]]>直接输入特殊字符即可
查询-多条件的查询
- 编写接口方法
- 参数:所有的查询条件
- 结果:List
- 编写SQL语句
- 执行方法,进行测试
- 思考SQL语句写法
- 参数传输
- 编写接口方法
多个查询条件进行参数传递
散装参数传递
对象参数传递
对象的属性名称要和参数占位符名称一致,否则无法封装
map集合参数传递
map集合中的键的名称要和参数占位符名称一致,否则无法封装
动态条件查询(动态SQL)
Mybatis对动态SQL有很强大的支撑:
if
多用于多条件的查询
if:条件判断
test:逻辑表达式
if标签中的逻辑表达式的&&要用and来进行代替,非空字符串用!=’’
逻辑表达式的字符用逻辑表达式中的数据
- 可能会出现where后直接跟上and,然后出现sql语法错误的问题,这时候可以使用
标签,或者在where后加入恒等式让所有条件格式一致 - 建议使用where标签,更加高效合理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<select id="selectByCondition" resultMap="brandResultMap">
select * from tb_brand
<where>
<if test="status!= null">
status= #{status}
</if>
<if test="companyName != null">
and company_name like #{companyName}
</if>
<if test="brandName!= null">
and brand_name like #{brandName};
</if>
</where>
</select>- 可能会出现where后直接跟上and,然后出现sql语法错误的问题,这时候可以使用
choose(when,otherwise)
从多个条件中选择其一
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<select id="selectByConditionSingle" resultMap="brandResultMap">
select * from tb_brand
<where>
<choose> <!--相当于switch-->
<when test="status!= null"><!--相当于 case-->
status =#{status}
</when>
<when test="companyName != null and companyName != ''">
company_name like #{companyName}
</when>
<when test="brandName != null and brandName != ''">
brand_name like #{brandName}
</when>
<!-- <otherwise>--><!--相当于default-->
<!-- 1=1-->
<!-- </otherwise>-->
</choose>
</where>
</select>trim(where,set)
foreach
添加
- 编写接口方法:Mapper接口
- 参数:除了id之外的所有数据,为了避免id主键重复
- 结果:void(通过是否出现异常确认是否成功)
- 编写SQL语句:SQL映射文件
mybatis会自动将autocommit设置为false,导致需要手动提交事务
如果需要自动提交事务,可以在获取sqlSession对象的时候设置参数
1 |
|
添加-主键返回
意思是在数据添加成功后,需要获取插入数据库数据 的主键的值
- 比如:添加订单和订单项
如果没有设置过主键返回
1 |
|
运行这段代码后,id的值是null,因为id是mysql自增生成的,并没有setId放入brand实体类当中
这时候就要设置mapper中的insert代码的 useGeneratedKeys和keyProperty属性
添加 useGeneratedKeys=”true” keyProperty=”id”
1 |
|
这样之后再运行sout(id);就会成功输出实际的id编号了
修改
修改全部字段
编写Mapper接口方法
参数:所有数据
结果:void
通过是否出现异常判断是否执行
编写SQL语句:SQL映射文件
执行方法,测试
要点与前面一致,根据业务逻辑编写SQL语句,Mapper代理运行SQL然后提交事务
修改动态字段
动态SQL进行修改语句
与动态条件查询类似,可以进行类比
不再赘述
删除
删除一个
编写Mapper接口方法
参数:id
结果:void
编写SQL语句:SQL映射文件
执行方法,测试
批量删除数据
因为批量删除需要的时候前端传输过来的一般多个数据,所以这时候获取的参数大概率是id数组
编写Mapper接口
参数:id数组
结果:void
编写SQL语句:SQL映射文件
执行方法,测试
批量删除数据和删除单条数据最大的区别在于SQL是动态的,因为批量删除数据时删除数据的数量是不确定的,在where id in (?,?,?) 这样的格式下面,?占位符 的数量是无法确定的,所有要使用动态SQL语句
mybatis会将传入的数组封装成Map集合
默认:array = 数组的key名称
使用@Param注解改变map集合的默认key的名称,比如传入参数的时候使用
(@Param(“ids”)int[] ids)
例子:
1 |
|
事务
1 |
|
MyBatis参数传递
MyBatis接口方法中可以接收各种各样的参数,MyBatis底层对于这些参数进行不同的封装处理
单个参数类型:
POJO类型:直接使用类型,属性名和参数占位符一致
Map集合:直接使用类型,键名和参数占位符一致
Collection:封装为Map集合
map.put(“arg0”,collection集合);
map.put(“collection”,collection集合);
List:封装为Map集合
map.put(“arg0”,list集合);
map.put(“collection”,list集合);
map.put(“list”,list集合);
Array:封装为Map集合
map.put(“arg0”,数组);
map.put(“array”,数组);
其他类型:可以直接使用,因为会直接调用这个参数放入到参数占位符的地方
多个参数类型:
封装成Map集合
map.put(“arg0”,参数值1)
map.put(“Param1”,参数值1)
map.put(“arg1”,参数值2)
map.put(“Param2”,参数值2)
如果使用@Param注解,来替换argX的键名
不要用默认的名称,使用@Param注解修改默认的键名,并且使用修改后的名称获取值,这样代码的可阅读性会更加高
注解开发
注解可以简化一些简单的SQL语句,但是复杂的SQL语句依旧是要用xml进行配置,不然会导致SQL语句从复杂变成混乱
可以直接在Mapper接口中这样写
1 |
|
这样可以直接代替在xml文件中写select标签
但是为了防止出现驼峰命名和_命名导致出现null的问题
需要在mybatis-config.xml文件配置以下设置,开启驼峰命名识别
1 |
|
完结
刚刚做综合练习
顺便附上我的servlet和jsp的maven坐标
1 |
|