目录
- MyBatis
- 创建MyBatis环境搭建
- MyBatis模式开发
- MyBatis 获取动态参数(查询操作)
- ${} 直接替换
- #{} 占位符模式替换
- like查询(模糊查询)
- 多表查询
- 一对一的表映射
- 一对多的表映射
- 增、删、改操作
- 改操作
- 删除操作
- 增加操作
- 添加用户
- 添加用户并获取用户id
- 返回类型与返回字典映射
- 返回类型 resultType
- 返回字典映射 resultMap
- 动态SQL
- \<if\>标签
- \<trim\>标签
- \<where\>标签
- \<set\>标签
- \<foreach\>标签
MyBatis是优秀的持久层框架,支持自定义SQL,存储过程以及高级映射。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
使用MyBatis是更简单完成程序和数据库交互的工具,可以更简单的操作和读取数据库工具。
MyBatis官网
MyBatis
MyBatis是基于JDBC的,在JDBC上又封装了一层
创建MyBatis环境搭建
和maven项目不同的两步:
- 添加MyBatis框架支持 (老项目 / 新项目)
- 设置MyBatis的配置信息
- 设置数据库链接的相关信息
- 配置 MyBatis xml 的保存路径和 xml 命名模式
# 数据库的连接字符串设置
spring.datasource.url=jdbc:mysql://localhost:3306/mycnblog?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=111
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# 设置MyBatis
mybatis.mapper-locations=classpath:/mybatis/*Mapper.xml
添加MyBatis框架支持
注意:第一次创建好了MyBatis项目之后,启动会报错。
需要在application.properties下设置数据库的连接字符串设置和 MyBatis 的 XML ⽂件配置。
# 数据库的连接字符串设置
spring.datasource.url=jdbc:mysql://localhost:3306/mycnblog?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=111
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# 设置MyBatis
mybatis.mapper-locations=classpath:/mybatis/*Mapper.xml
MyBatis模式开发
MyBatis模式开发由两部分组成
- interface :让其他层可以注入使用的接口
- MyBatis xml:具体实现sql【他是上面interface的实现】
MyBatis 获取动态参数(查询操作)
${} 直接替换
MyBatis 获取动态参数有两种实现:
- ${paramName} 直接替换
<select id="getUserById" resultType="com.example.demo.entity.UserEntity">select * from userinfo where id=${uid}
<!-- 如果param和形参中的值不一样,需要使用@Param中的参数 --></select>
#{} 占位符模式替换
- #{paramName} 占位符模式
是一种预执行,可以有效的排除SQL的安全问题
<select id="getUserById" resultType="com.example.demo.entity.UserEntity">select * from userinfo where id=#{uid}</select>
@Testvoid login() {String username = "admin";String password = "' or 1='1";UserEntity inputUser = new UserEntity();inputUser.setUsername(username);inputUser.setPassword(password);UserEntity user = userMapper.login(inputUser);System.out.println(user);}
<select id="login" resultType="com.example.demo.entity.UserEntity">select * from userinfo where username='${username}' and password='${password}'</select>
没有输入密码,但是可以构造,得到用户数据
$:直接替换
只要or前后有一个条件满足即可
select * from userinfo where username='${username}' and password='' or 1='1'
#是预执行处理,填充的东西只看做一个字符串,不会查到用户数据
<select id="login" resultType="com.example.demo.entity.UserEntity">select * from userinfo where username=#{username} and password=#{password}</select>
$:直接替换,当需要传递一个SQL关键字的时候比较适合使用
比如需要对数据进行倒序或者正序排序时
//UserMapper.javaList<UserEntity> getAllByIdOrder(@Param("ord") String ord);
//UserMapper.xml<select id="getAllByIdOrder" resultType="com.example.demo.entity.UserEntity">select * from userinfo order by id ${ord}</select>
//UserMapperTest@Testvoid getAllByIdOrder() {List<UserEntity> list = userMapper.getAllByIdOrder("desc");System.out.println(list.size());}
like查询(模糊查询)
//根据用户名模糊查询List<UserEntity> getListByName(@Param("username") String username);
<select id="getListByName" resultType="com.example.demo.entity.UserEntity">select * from userinfo where username like concat('%', #{username},'%')</select>
@Testvoid getListByName() {String username = "oo";List<UserEntity> list = userMapper.getListByName(username);list.stream().forEach(System.out::println);}
多表查询
一对一的表映射
(企业中几乎不用)
一对多的表映射
增、删、改操作
改操作
修改密码
//UserMapper.java//修改密码int updatePassword(@Param("id")Integer id,@Param("password") String password,@Param("newPassword") String newPassword);
<!-- UserMapper.xml -->
<!-- select 要求必须设置两个属性,update设置一个参数就行,update默认会返回一个受影响的行数,返回类型默认是int --><update id="updatePassword">update userinfo set password=#{newPassword}where id=#{id} and password=#{password}</update>
在UserMapper.java下右键生成updatePassword的Test
//UserMapperTest.java@Transactional //事务(执行前新建事务,执行完进行回滚) 该注解让操作不污染数据库,可以加在类上,也可以加在方法上。@Testvoid updatePassword() {int result = userMapper.updatePassword(1, "123456", "aaaaa");System.out.println("修改:" + result);}
删除操作
//UserMapper.java//删除用户int delById(@Param("id") Integer id);
<!-- UserMapper.xml -->
<!-- 删除 --><delete id="delById">delete from userinfo where id=#{id}</delete>
//UserMapperTest.java@Transactional@Testvoid delById() {int id = 1;int result = userMapper.delById(id);System.out.println("删除结果:" + result);}
增加操作
添加用户
//UserMapper.java//添加操作int addUser(UserEntity user);
<!-- UserMapper.xml -->
<!-- 添加 返回影响行数--><insert id="addUser">insert into userinfo(username, password) values(#{username}, #{password})</insert>
//UserMapperTest.java@Testvoid addUser() {UserEntity user = new UserEntity();user.setUsername("root");user.setPassword("123456");int result = userMapper.addUser(user);System.out.println("添加用户" + result);}
添加用户并获取用户id
//UserMapper.javaint addUserGetId(UserEntity user);
<!-- UserMapper.xml -->
<!-- 数据库中要给id设置自增主键,不然这些会报错 -->
<!-- useGeneratedKeys="true" 表示是否自动生成id(主键) 默认为false -->
<!-- 开启自动生成主键后,keyProperty表示将生成的主键赋值给哪个属性字段上,放在id字段 -->
<!-- 添加 返回影响行数 和 id--><insert id="addUserGetId" useGeneratedKeys="true" keyProperty="id">insert into userinfo(username, password) values(#{username}, #{password})</insert>
//UserMapperTest.java@Testvoid addUserGetId() {UserEntity user = new UserEntity();user.setUsername("root");user.setPassword("123456");int result = userMapper.addUserGetId(user);System.out.println("添加结果:" + result);System.out.println("ID:" + user.getId());}
返回类型与返回字典映射
返回类型 resultType
大多数的场景都可以使用resultType进行返回。使用方便,直接定义实体类即可
返回字典映射 resultMap
resultMap的使用场景
- 字段名称和程序中的属性名不同,使用resultMap配置映射
- 一对一和一对多关系可以使用resultMap映射并查询数据
动态SQL
动态SQL是MyBatis的强大特性之一,能够描述不同条件下不同SQL的拼接。允许在XML中写逻辑判断
保证了数据的一致性
<if>标签
有时候有必填字段和⾮必填字段,如果在添加的时候有不确定的字段传⼊,需要使用动态标签 <if> 判断
int addUser2(UserEntity user);
<insert id="addUser2">insert into userinfo(username, password<if test="photo != null and photo !=''"> <!-- 这里test里面判断的key是属性,不是数据库字段 -->,photo <!-- 数据库字段 --></if>) values(#{username}, #{pwd}<if test="photo != null and photo !=''">,#{photo} <!-- 这里是属性,不是数据库字段 (特殊字符 #{} 等,里面的都属于程序里面的) --></if>)</insert>
@Transactional@Testvoid addUser2() {String username = "ss";String password = "1008611";String photo = "this is a photo";UserEntity user = new UserEntity();user.setUsername(username);user.setPwd(password);user.setPhoto(photo);int result = userMapper.addUser2(user);System.out.println("添加:" + result);}
<trim>标签
如果所有的字段都是非必填的情况下,只使用if标签就无法解决问题了。
就要使用<trim>
标签结合<if>
标签,对多个字段都采取动态生成的方式。
<trim>
标签属性:
- prefix:整个语句块,以prefix的值为前缀
- suffix:整个语句块,以suffix的值作为后缀
- prefixOverrides:表示整个语句块要去除的前缀,有则去除,没有也不会报错
- suffixOverrides:表示整个语句块要去除的后缀
<trim>
标签的处理方法:
- 基于
prefix
配置,在开始部分加上(
- 基于
suffix
配置,在结束部分加)
- 在多个
<if>
组织的语句后都以,
结尾,在最后拼接好的字符串还会以,
结尾,会基于suffixOverrides配置去掉最后一个,
<if test="createTime!=null">
中的 createTime 是传入对象的属性
使用 trim 什么都不传的话会报错
select * from articleinfo
where
<trim suffixOverrides="and"><if test="id != null and id > 0">id=#{id} and</if><if test="title != null and title != ''">title like concat('%', #{title},'%')</if>
</trim>
当MyBatis中多个都是非必传参数的解决方案:
① 1=1
<!--除非在最前面加上 1=1 -->
<!-- 这样是可行的 -->
select * from articleinfo
where 1=1
<trim prefixOverrides="and"><if test="id != null and id > 0">and id=#{id}</if><if test="title != null and title != ''">and title like concat('%', #{title},'%')</if>
</trim>
② 在trim中使用where作为前缀和and作为整个语句块要去除的后缀
当trim中生成了代码,才会添加<trim>
中的前缀和后缀,如果trim中没有生成代码,前缀和后缀都会省略
<select id="getListByIdOrTitle" resultType="com.example.demo.entity.VO.ArticleInfoVO">select * from articleinfo<trim prefix="where" suffixOverrides="and"><if test="id != null and id > 0">id=#{id} and</if><if test="title != null and title != ''">title like concat('%', #{title},'%')</if></trim>
</select>
③ where标签
<where>标签
where标签是专门用来解决多个都是非必传参数的。
<where>
会自动帮你取出最前面的 and 关键字,但要注意,使用where标签不会自动帮你去除最后的and标签。
where 会自动检测 <where>
内是否有数据传入,如果没有就不会生成where语句
select * from articleinfo
<where><if test="id != null and id > 0">id=#{id}</if><if test="title != null and title != ''">and title like concat('%', #{title},'%')</if>
</where>
<set>标签
<set>
会自动取出最后面的关键字。
<update id="updateById" parameterType="org.example.model.User">update user<set><if test="username != null">username=#{username},</if><if test="password != null">password=#{password},</if><if test="sex != null">sex=#{sex},</if></set>where id=#{id}
</update>
<foreach>标签
对集合进行遍历
常用属性:
- collection:传递过来的集合的名称,List,set,map或数组
- item:集合中遍历的每一个对象
- open:语句块开头的字符串
- close:语句块结束的字符串
- separator:每次遍历之间间隔的分隔符
使用foreach 标签最常见的使用:批量删除