MyBatis
MyBatis是一款持久层框架,用于简化JDBC开发。
-
持久层
- 负责将数据保存到数据库的代码
- JavaEE三层架构:表现层、业务层、持久层
-
框架
- 框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型
- 在框架的基础上建构软件编写更加高效、规范、通用、可拓展
-
JDBC缺点
-
硬编码
注册驱动,获取连接
SQL语句
-
操作繁琐
手动设置参数
手动封装结果集
-
-
MyBatis简化
- 硬编码-->配置文件
- 操作繁琐-->自动完成
MyBatis几乎免除了所有的JDBC代码以及设置参数和获取结果集的工作
MyBatis快速入门
编写MyBatis核心配置文件 --> 替换连接信息 解决硬编码问题
<?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.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test?useServerPrepStmts=true"/>
<property name="username" value="root"/>
<property name="password" value="122381"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 加载sql映射文件-->
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
编写SQL映射文件 --> 统一管理sql语句,解决硬编码问题
编码
-
加载核心配置文件,获取
SqlSessionFactory
对象String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
-
获取
SqlSession
对象,执行SQL语句SqlSession session = sqlSessionFactory.openSession(); //参数是SQL映射问件的名称空间.id List<User> users = session.selectList("user.selectAll");
-
释放资源
session.close();
Mapper代理开发
目的
-
解决原生方式中的硬编码问题
如:
List<User> users = session.selectList("user.selectAll");
更改为:
//获取接口代理对象 UserMapper userMapper = session.getMapper(UserMapper.class); //执行方法,也就是执行sql语句 List<User> users = userMapper.selectAll();
-
简化后期执行SQL
使用Mapper代理开发步骤
- 定义与SQL映射文件同名的Mapper接口,并将Mapper接口和SQL映射文件放置在同一目录下
- 设置SQL映射文件的namespace属性为Mapper接口全类名
- 在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致
细节:如果Mapper接口的名称和SQL映射文件名称相同,并在同一目录下,可以使用包扫描的方式简化SQL映射文件的加载
<!-- MyBatis核心配置文件-->
<mappers>
<!-- 加载sql映射文件-->
<!-- <mapper resource="UserMapper.xml"/>-->
<!-- 如果Mapper接口的名称和SQL映射文件名称相同,并在同一目录下,可以使用包扫描的方式简化SQL映射文件的加载-->
<package name="mapper"/>
</mappers>
MyBatis核心配置文件
配置各个标签时,需要注意约束的先后顺序
environments
配置数据库连接环境信息,可以配置多个environment,通过default属性切换不同的environment
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test?useServerPrepStmts=true"/>
<property name="username" value="root"/>
<property name="password" value="122381"/>
</dataSource>
</environment>
</environments>
transactionManager与dataSource均会被spring管理
typeAliases
<typeAliases>
<!-- 类型别名,在SQL映射文件中,resultType对指定包下的类可以直接用不区分大小写的类名代替全类名-->
<package name="domain"/>
</typeAliases>
配置文件完成增删改查
查询
查询所有数据
List<User> selectAll();
<select id="selectAll" resultType="User">
select * from user
</select>
<!-- 数据库的字段名称和实体类字段名称不一样时,不能自动封装-->
<!-- 可以通过起别名来解决-->
<select id="selectAll" resultType="User">
select name as name, password as password from user
</select>
<!-- 也可以通过定义、引用sql片段来解决-->
<sql id="user_column">
name as name, password as password
</sql>
<select id="selectAll" resultType="User">
select <include refid="user_column"></include> from user
</select>
<!-- 通过resultMap解决-->
<!-- id: 唯一标识 type: 映射的类型-->
<resultMap id="UserResultMap" type="User">
<!-- id: 用于主键字段的映射-->
<!-- result: 用于普通字段的映射-->
<!-- column: 表的列名 property: 实体类的名称-->
<result column="name" property="name"></result>
<result column="password" property="password"></result>
</resultMap>
<select id="selectAll" resultMap="UserResultMap">
select * from user
</select>
查询某条数据
User selectByName(String name);
<!-- #{}:执行SQL时,会将其替换为?,将来自动设置参数-->
<!-- ${}:拼接SQL,会出现SQL注入问题-->
<!-- 参数类型:parameterType可以省略-->
<select id="selectByName" parameterType="string" resultType="User">
select * from user where name = #{name}
</select>
<!-- 特殊字符:转义字符;CDATA区-->
<select id="selectById" resultType="User">
select * from user where id < #{id}
</select>
<select id="selectById" resultType="User">
select * from user where id
<![CDATA[
<
]]>
#{id}
</select>
条件查询
// 散装参数:如果方法中有多个参数,需要使用@Param("SQL参数占位符名称")
List<User> selectByCondition(@Param("name") String name, @Param("password") String password);
// 对象参数:对象属性名称要与SQL参数占位符名称一致
List<User> selectByCondition(User user);
// Map参数:Map集合的键的名称要与SQL参数占位符名称一致,值就是想要传递的参数值
List<User> selectByCondition(Map map);
<select id="selectByCondition" resultType="User">
select * from user where name = #{name} and password = #{password}
</select>
动态查询
List<User> selectDynamic(User user);
<select id="selectDynamic" resultType="User">
select * from user
<where>
<if test="id != null and id != 0">
and id = #{id}
</if>
<if test="name != null">
and name = #{name}
</if>
<if test="password != null">
and password = #{password}
</if>
</where>
</select>
List<User> selectUserIn(List<String> users);
<select id="selectUserIn" resultType="User">
select * from user where
<choose>
<when test="list.isEmpty()">
1 = 0
</when>
<otherwise>
name in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")" nullable="true">
#{item}
</foreach>
</otherwise>
</choose>
</select>
MyBatis事务
openSession() //默认开启事务,进行增删改操作后,要使用session.commit()手动提交事务
openSession(true) //设置为自动提交(关闭事务)
增加
void add(User user);
<!-- useGeneratedKeys和keyProperty属性,将添加数据后,数据库自动生成的id返回并设置到传入对象的指定字段-->
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into user (name, password) values (#{name}, #{password})
</insert>
修改
修改全部字段
void update(User user);
<update id="update">
update user set name = #{name}, password = #{password}
where id = #{id}
</update>
修改动态字段
void updateDynamic(User user);
<update id="updateDynamic">
update user
<set>
<if test="name != null">
name = #{name},
</if>
<if test="password != null">
password = #{password},
</if>
</set>
where id = #{id}
</update>
删除
删除一个
void deleteById();
<delete id="deleteById">
delete from user where id = #{id};
</delete>
批量删除
void deleteByIds(List<Integer> ids);
<delete id="deleteByIds">
delete from user where
<choose>
<when test="list.isEmpty()">
1 = 0
</when>
<otherwise>
<foreach item="id" index="index" collection="list"
open="(" close=")">
#{id}
</foreach>
</otherwise>
</choose>
</delete>
动态SQL
SQL语句会随着用户的输入或外部条件的变化而变化,称为动态SQL
if
choose (when, otherwise)
trim (where, set)
foreach
以下样内容来自官方文档
if
使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。比如:
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
这条语句提供了可选的查找文本功能。如果不传入 “title”,那么所有处于 “ACTIVE” 状态的 BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果(细心的读者可能会发现,“title” 的参数值需要包含查找掩码或通配符字符)。
如果希望通过 “title” 和 “author” 两个参数进行可选搜索该怎么办呢?首先,我想先将语句名称修改成更名副其实的名称;接下来,只需要加入另一个条件即可。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员精选的 Blog)。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
trim、where、set
前面几个例子已经方便地解决了一个臭名昭著的动态 SQL 问题。现在回到之前的 “if” 示例,这次我们将 “state = ‘ACTIVE’” 设置成动态条件,看看会发生什么。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:
SELECT * FROM BLOG
WHERE
这会导致查询失败。如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:
SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
这个查询也会失败。这个问题不能简单地用条件元素来解决。这个问题是如此的难以解决,以至于解决过的人不会再想碰到这种问题。
MyBatis 有一个简单且适合大多数场景的解决办法。而在其他场景中,可以对其进行自定义以符合需求。而这,只需要一处简单的改动:
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
或者,你可以通过使用trim元素来达到同样的效果:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
注意,我们覆盖了后缀值设置,并且自定义了前缀值。
foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
<where>
<foreach item="item" index="index" collection="list"
open="ID in (" separator="," close=")" nullable="true">
#{item}
</foreach>
</where>
</select>
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
上例中,若传入的可迭代对象中元素个数为0,相当于执行select * from post p
,返回全部元素
因此,要在程序中提前判断,若要查询的集合为空即可不用执行查询
MyBatis参数传递
单个参数
-
POJO类型
直接使用,保证属性名和参数占位符名称一致
-
Map集合
直接使用,保证Map集合的键名和参数占位符名称一致
-
Collection
map.put("arg0", collection集合) map.put("collection", collection集合)
-
List
map.put("arg0", list集合) map.put("collection", list集合) map.put("list", list集合)
-
Arraay
map.put("arg0", 数组) map.put("array", 数组)
-
其他类型
多个参数
封装为Map集合
map.put("arg0", 参数值1)
map.put("param1", 参数值1)
……
注解完成增删改查
使用注解完成简单功能
配置文件完成复杂功能
@Select("select * from user where id = #{id}")
User selectById(int id);
标签:name,title,user,SQL,MyBatis,where,id
From: https://www.cnblogs.com/Lerjiu/p/17291159.html