MyBatis学习笔记
MyBatis
- controller 控制层
- service 业务层
- dao 持久层
MyBatis是一款优秀的持久层框架,用于简化JDBC的开发。
MyBatis本是Apache的一个开源项目iBatis,2010年这个项目由apache迁移到了google code,并且改名为MyBatis。2013年11月迁移到GitHub
MyBatis入门
快速入门
使用MyBatis查询所有用户数据
- 准备工作(创建SpringBoot工程、数据库表user、实体类User)
- 引入MyBatis的相关依赖、配置MyBatis
- 编写SQL语句(注解/XML)
package com.itheima;
import com.itheima.mapper.UserMapper;
import com.itheima.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest //springboot整合单元测试的注解
class SpringbootMybatisQuickstartApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testListUser(){
List<User> userList = userMapper.list();
userList.stream().forEach(user -> {
System.out.println(user);
});
}
}
package com.itheima.pojo;
public class User {
private Integer id;
private String name;
private Short age;
private Short gender;
private String phone;
public User() {
}
public User(Integer id, String name, Short age, Short gender, String phone) {
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
this.phone = phone;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Short getAge() {
return age;
}
public void setAge(Short age) {
this.age = age;
}
public Short getGender() {
return gender;
}
public void setGender(Short gender) {
this.gender = gender;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
", phone='" + phone + '\'' +
'}';
}
}
package com.itheima.mapper;
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper //运行时,会自动生成该接口的实现类对象(代理对象),并且将对象交给IOC容器管理
public interface UserMapper {
/*查询所有用户信息*/
@Select("select * from user")
public List<User> list();
}
JDBC介绍
JDBC:(Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API。
本质:
- sun公示官方定义的一套操作所有关系型数据库的规范,即接口。
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包。
- 可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
数据库连接池
数据库连接池:
- 数据库连接池是个容器,负责分配、管理数据库连接(Connection)
- 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
- 释放空闲时间超过最大空闲时间的连接,来比米娜因为没有释放连接而引起的数据库连接遗漏。
优势:
- 资源重用
- 提升系统的响应速度
- 避免数据库连接遗漏问题
标准接口: DataSource
- 官方(sun)提供的数据库连接池接口,由第三方组织实现此接口
- 功能:获取连接
Connection getConnection() throws SQLException;
com.zaxxer.hikari.HikariDataSource
- 产品: C3P0、DBCP、Druid、Hikari
lombok
- Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化Java开发,提高效率
注解 | 作用 |
---|---|
@Getter/@Setter | 为所有的属性提供get/set方法 |
@ToString | 会给类自动生成易于阅读的toString方法 |
@EqualsAndHashCode | 根据类所拥有的非静态字段自动重写equals方法和hashCode方法 |
@Data | 提供了更综合的生成代码功能(@Getter+@Setter+@ToString+@EqualsAndHashCode) |
@NoArgConstructor | 为实体类生成无参的构造器方法 |
@AllArgConstructor | 为实体类生成除了static修饰的字段之外带有各参数的构造器方法。 |
引入lombok依赖
<dependency>
<groupld>org.projectlombok</groupld>
<artifactld>lombok</artifactld>
</dependency>
//不使用lombok注解
package com.itheima.pojo;
public class User {
private Integer id;
private String name;
private Short age;
private Short gender;
private String phone;
public User() {
}
public User(Integer id, String name, Short age, Short gender, String phone) {
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
this.phone = phone;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Short getAge() {
return age;
}
public void setAge(Short age) {
this.age = age;
}
public Short getGender() {
return gender;
}
public void setGender(Short gender) {
this.gender = gender;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
", phone='" + phone + '\'' +
'}';
}
}
//使用lombok注解
package com.itheima.pojo;
import lombok.*;
@Data
@NoArgsConstructor //无参构造
@AllArgsConstructor //全参构造
public class User {
private Integer id;
private String name;
private Short age;
private Short gender;
private String phone;
}
注意事项:
Lombok会在编译时,自动生成对应的Java代码。使用Lombok时,需要安装一个Lombok插件(IDEA自带)
MyBatis基础操作
环境准备
准备工作
- 准备数据库表emp
- 创建一个新的springboot工程,选择引入对应的起步依赖(Mybatis、MySQL)
- application.properties中引入数据库连接信息
- 创建对应的实体类Emp(实体类属性采用驼峰命名)
- 准备Mapper接口EmpMapper
删除功能
- SQL语句
delete from emp where id = 17;
- 接口方法
@Delete("delete from emp where id = #{id}")
public void delete(Integer id)
注意事项
如果mapper接口方法形参只有一个普通类型的参数,#{…}里面的属性名额可以随便写,如#{id}、#{value}
日志输出
- 可以在application.properties中,打开mybatis的日志,并指定输出到控制台中
# 配置mybatis的日志,指定输出到控制台中
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
预编译SQL
-
优势:
- 性能更高
- 更安全(防止SQL注入)
SQL注入是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法
参数占位符
- #{…}
- 执行SQL时,会将#{…}替换为?,生成预编译SQL,会自动设置参数值
- 使用时机:参数传递,都是用#{…}
- ${…}
- 拼接SQL,直接将参数拼接在SQL语句,存在SQL注入问题
- 使用时机:如果对表名、列表进行动态设置时使用
新增功能
# 插入数据的SQL语句
insert into emp(username,name,gender,image,job,entrydate,dept_id,create_time,update_time)
values ('Tom','汤姆',1,'1.jpg',1,'2005-01-01',1,now(),now())
//EmpMapper中
//新增员工
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
" values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
public void insert(Emp emp);
//SpringBootMybatisQuickstartApplicationTest中
@Test
public void testInsert(){
//构造员工对象
Emp emp = new Emp();
emp.setUsername("Tom");
emp.setName("汤姆");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setEntrydate(LocalDate.of(2000,1,1));
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(1);
//执行新增员工信息操作
empMapper.insert(emp);
}
新增(主键返回)
- 描述:在数据添加成功后,需要获取插入数据库数据的主键。
@Test
public void testInsert(){
//构造员工对象
Emp emp = new Emp();
emp.setUsername("Tom2");
emp.setName("汤姆2");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setEntrydate(LocalDate.of(2000,1,1));
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(1);
//执行新增员工信息操作
empMapper.insert(emp);
System.out.println(emp.getId());
}
//System.out.println(emp.getId())
//null
- 实现:使用@Options注解
//新增员工
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
" values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
public void insert(Emp emp);
@Test
public void testInsert(){
//构造员工对象
Emp emp = new Emp();
emp.setUsername("Tom3");
emp.setName("汤姆3");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setEntrydate(LocalDate.of(2000,1,1));
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(1);
//执行新增员工信息操作
empMapper.insert(emp);
System.out.println(emp.getId());
}
//输出20
更新功能
#MySQL语句的更新
update emp set username='',name = '',gender = '',image = '',job = '',entrydate = '',dept_id = '',update_time = '' where id = 1;
//更新员工
@Test
public void testUpdate(){
//构造员工对象
Emp emp = new Emp();
emp.setId(18);
emp.setUsername("Tom1");
emp.setName("汤姆1");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setJob((short)1);
emp.setEntrydate(LocalDate.of(2000,1,1));
emp.setCreateTime(LocalDateTime.now());
emp.setDeptId(1);
//执行更新员工操作
empMapper.update(emp);
}
//更新员工
@Update("update emp set username = #{username}, name = #{name}, gender = #{gender}, image = #{image}," +
" job = #{job}, entrydate = #{entrydate}, dept_id = #{deptId},update_time = #{updateTime} where id = #{id}")
public void update(Emp emp);
查询(根据ID查询)
#MySQL语句
select * from emp where id = 1;
//根据ID查询员工
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
public void testSelectEmp(){
Emp emp = empMapper.getById(20);
System.out.println(emp);
}
//输出dept_id create_time update_time为null
数据封装
- 实体类属性名 和 数据库表查询返回的字段名一直,mybatis会自动封装
- 如果实体类属性名 和 数据库表查询返回的字段名不一致,不能自动封装
解决方案(数据封装)
- 方案一:手动起别名
@Select("select id, username, password, name, gender, image, job, entrydate," +
" dept_id deptId, create_time createTime, update_time updateTime from emp where id = #{id}")
public Emp getById(Integer id);
- 方案二:使用@Result注解
@Results({
@Result(column = "dept_id" ,property = "deptId"),
@Result(column = "create_time" ,property = "createTime"),
@Result(column = "update_time" ,property = "updateTime")
})
@Select("select id, username, password, name, gender, image, job, entrydate," +
" dept_id deptId, create_time createTime, update_time updateTime from emp where id = #{id}")
public Emp getById(Integer id);
- 方案三:开启mybatis的驼峰自动映射开关
在application.properties中
# 开启mybatis的驼峰命名自动映射开关
mybatis.configuration.map-underscore-to-camel-case=true
查询(条件查询)
MySQL语句—条件查询
select * from emp where name like '%张%' and gender = 1 and entrydate between '2010-01-01' and '2020-01-01' order by update_time desc ;
@Select("select * from emp where name like '%${name}%' and gender = #{gender} and " +
"entrydate between #{begin} and #{end} order by update_time desc ")
public List<Emp> list(@Param(value = "name") String name,
@Param(value = "gender") Short gender,
@Param(value = "begin") LocalDate begin,
@Param(value = "end") LocalDate end);
//不是预编译,可能存在SQL注入
改进方法:
使用SQL提供的concat字符串拼接函数:
select * from emp where name like concat('%','张','%') and gender = 1 and entrydate between '2010-01-01' and '2020-01-01' order by update_time desc ;
@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and " +
"entrydate between #{begin} and #{end} order by update_time desc ")
public List<Emp> list(@Param(value = "name") String name,
@Param(value = "gender") Short gender,
@Param(value = "begin") LocalDate begin,
@Param(value = "end") LocalDate end);
XML映射文件
规范:
- XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
- XML映射文件的namespace属性为Mapper接口全限定名一致
- XML映射文件中SQL语句的id与Mapper接口中的方法名一致,并保持返回类型一致。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
使用Mybatis的注解,主要是用来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句
MyBatis动态SQL
动态SQL:随着用户的输入或外部条件的变化而变化的SQL语句,称为动态SQL语句
<if>
标签
if标签用于判断条件是否成立,使用test属性进行条件判断,如果条件为true,则拼接SQL
<where>
标签
where元素只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或OR.
<mapper namespace="com.itheima.mapper.EmpMapper">
<select id="list" resultType="com.itheima.pojo.Emp">
select *
from emp
<where>
<if test="name != null">
name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>
</mapper>
@Test
public void testList(){
// List<Emp> empList = empMapper.list(
// "张", (short) 1, LocalDate.of(2010, 1, 1), LocalDate.of(2020, 1, 1));
List<Emp> empList = empMapper.list("张", null, null, null);
//List<Emp> empList = empMapper.list("张", (short)1, null, null);
//List<Emp> empList = empMapper.list(null, (short)1, null, null);
// List<Emp> empList = empMapper.list(null, null, null, null);
System.out.println(empList);
}
案例
使用动态更新员工 - 更新id为18的员工,username更新为Tom111,name更新为汤姆111,gender更新为2
@Test public void testUpdate(){ //构造员工对象 Emp emp = new Emp(); emp.setId(18); emp.setUsername("Tom111" emp.setName("汤姆111"); emp.setImage("1.jpg"); emp.setGender((short)2); //执行更新员工操作 empMapper.update(emp); }
会导致其他信息为null
需要:动态更新员工信息,如果更新时有传递值,则更新;如果更新时没有传递值,则不更新
<update id="update2">
update emp
<set>
<if test="username != null">username = #{username},</if>
<if test="name != null">name = #{name},</if>
<if test="gender != null">gender = #{gender},</if>
<if test="image != null">image = #{image},</if>
<if test="job != null">job = #{job},</if>
<if test="entrydate != null">entrydate = #{entrydate},</if>
<if test="deptId != null">dept_id = #{deptId},</if>
<if test="updateTime != null">update_time = #{updateTime}</if>
</set>
where id = #{id}
</update>
<foreach>
标签
批量删除SQL语句:
delete
from emp
where id in (18,19,20);
使用Mybatis完成批量删除需求
//测试类
@Test
public void testDeleteByIds(){
List<Integer> ids = Arrays.asList(13, 14, 15);
empMapper.deleteByIds(ids);
}
//Mapper接口
//批量删除员工
public void deleteByIds(@Param(value = "ids") List<Integer> ids);
<!--SQL映射-->
<!--批量删除员工 (18,19,20)-->
<!--
collection: 遍历的集合
item: 遍历出来的元素
separator: 分隔符
open: 遍历开始前拼接的SQL片段
close: 遍历结束后拼接的SQL片段
-->
<delete id="deleteByIds">
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<sql>、<include>
标签
<sql>
定义可重用的SQL片段<include>
通过属性refid,指定包含的sql片段
<sql id="commonSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time
from emp
</sql>
<select id="list" resultType="com.itheima.pojo.Emp">
<include refid="commonSelect"/>
<where>
<if test="name != null">
name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>
原文地址:https://blog.csdn.net/qq_35899077/article/details/144276260
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!