Mybatis入门——基础操作(基于springboot项目)
Mybatis入门
介绍
什么是Mybatis?
- Mybatis是一款优秀的 持久层 框架,用于简化JDBC的开发。
- Mybatis本是Apache的一个开源项目iBatis,2010年这个项目由apache迁移到了goole code,并且改名为Mybatis,2013年11月迁移到GitHub。
- 官网:https://mybatis.org/mybatis-3/zh_CN/index.html
快速入门
使用mybatis查找所有用户
- 准备工作(创建springboot工程,数据表user、实体类User)
- 引入Mybatis的相关依赖,配置Mybatis
- 编写SQL语句(注解/XML)
创建springboot模块
点击下一步
springboot版本
具体含义,如下文所示:
- SNAPSHOT:快照版,表示开发版本,随时可能修改;
- M1(Mn):M是milestone的缩写,也就是里程碑版本;
- RC1(RCn):RC是release candidates的缩写,也就是发布预览版;
- Release:正式版,也可能没有任何后缀也表示正式版
点击创建,IDEA会自动下载依赖,完成项目的创建
可以将这些不需要的文件删除
导入MyBatis Framework和Mysql Driver
pox.xml中的依赖
<!--mybatis起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<!--mysql的驱动包,最新版本的驱动包-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!--spring boot单元测试的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
创建user数据库
create table user(
id int unsigned primary key auto_increment comment 'ID',
name varchar(100) comment '姓名',
age tinyint unsigned comment '年龄',
gender tinyint unsigned comment '性别, 1:男, 2:女',
phone varchar(11) comment '手机号'
) comment '用户表';
insert into user(id, name, age, gender, phone) VALUES (null,'白眉鹰王',55,'1','18800000000');
insert into user(id, name, age, gender, phone) VALUES (null,'金毛狮王',45,'1','18800000001');
insert into user(id, name, age, gender, phone) VALUES (null,'青翼蝠王',38,'1','18800000002');
insert into user(id, name, age, gender, phone) VALUES (null,'紫衫龙王',42,'2','18800000003');
insert into user(id, name, age, gender, phone) VALUES (null,'光明左使',37,'1','18800000004');
insert into user(id, name, age, gender, phone) VALUES (null,'光明右使',48,'1','18800000005');
创建实体类对象
点击查看代码
package minm.pojo;
/**
* @author minm
* @version 1.0
* @description: TODO
* @date 2024/4/28 上午12:42
*/
public class User {
private Integer id;
private String name;
private Integer age;
private Integer gender;
private String phone;
public User() {
}
public User(Integer id, String name, Integer age, Integer 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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer 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 + '\'' +
'}';
}
}
创建接口
使用测试类,测试
测试类路径
src/test/java/minm/SpringbootMybatisQuickstartApplicationTests.java
JDBC介绍
JDBC:就是使用Java语言操作关系型数据库的一套API
本质
- sun公司官方定义的一套操作所有关系型数据库的规范,及接口。
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包
- 我们可以使用这套接口(JDBC)变成,真正执行的代码时驱动jar包中的实现类
点击查看代码:JDBC连接数据库
@Test
public void testJdbc() throws Exception {
//连接数据库
String url = "jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "21MINM";
//创建连接
Connection connection = DriverManager.getConnection(url, username, password);
//创建statement
Statement statement = connection.createStatement();
//执行sql
String sql = "select * from user";
ResultSet resultSet = statement.executeQuery(sql);
//处理结果集
while (resultSet.next()) {
Integer id = resultSet.getInt("id");
String name = resultSet.getString("name");
Integer age = resultSet.getInt("age");
Integer gender = resultSet.getInt("gender");
String phone = resultSet.getString("phone");
System.out.println(id + " " + name + " " + age + " " + (gender == 1 ? "男" : "女") + " " + phone + " \n");
}
//关闭资源
resultSet.close();
statement.close();
connection.close();
}
数据库连接池
- 数据库连接池是个容器,负责分配、管理数据库连接(connection)
- 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
- 释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引发的数据库连接遗漏
优势
- 资源重用
- 提升系统响应速度
- 避免数据库连接遗漏
标准接口:DataSource
- 官方提供的数据库连接池接口,由第三方组织实现此接口
- 功能:获取连接 connection getConnection() throws SQLException;
springboot自带Hikari连接池
- Druid(德鲁伊)
- Druid连接池时阿里巴巴开源的数据库连接池项目
- 功能强大,性能优秀,时java语言最好的数据库连接池之一
导入依赖https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter
点击查看代码
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.22</version>
</dependency>
点击查看代码
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource #引入druid数据源
#数据源基本信息,也可放在druid下
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
#SpringBoot因为默认是hikari数据源所以对于其他数据源默认是不注入这些属性的,需要手动配置
#druid数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 600000
# 主要配置以上几个即可
Lombok
- Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提升效率
注解 | 作用 |
---|---|
@Getter/@Setter | 为所有的属性提供get/set方法 |
@ToString | 会给类自动生成易阅读的toString方法 |
@EqualsAndHashCode | 根据类所拥有的非静态字段自动重写equals方法和hashCode方法 |
@Data | 提供了更加综合的生成代码功能(@Getter + @Setter + @ToString + @EqualsAndHashCode) |
@NoArgsConstructor | 为实体类生成无参的构造器方法 |
@AllArgConstructor | 为实体类生成除了static修饰的字符之外带有个参数的构造器方法 |
- Lombok会在编译时,自动生成对应的java代码。我们使用lombok时,还需要安装一个lombok的插件(idea自带)
mybatis基础操作
准备工作
- 准备数据库表emp
- 创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)
- application.properties中引入数据库连接信息
- 创建对应的实体类Emp(实体类属性采用驼峰命名)
- 准备Mapper接口EmpMapper
数据库
create table user(
id int unsigned primary key auto_increment comment 'ID',
name varchar(100) comment '姓名',
age tinyint unsigned comment '年龄',
gender tinyint unsigned comment '性别, 1:男, 2:女',
phone varchar(11) comment '手机号'
) comment '用户表';
insert into user(id, name, age, gender, phone) VALUES (null,'白眉鹰王',55,'1','18800000000');
insert into user(id, name, age, gender, phone) VALUES (null,'金毛狮王',45,'1','18800000001');
insert into user(id, name, age, gender, phone) VALUES (null,'青翼蝠王',38,'1','18800000002');
insert into user(id, name, age, gender, phone) VALUES (null,'紫衫龙王',42,'2','18800000003');
insert into user(id, name, age, gender, phone) VALUES (null,'光明左使',37,'1','18800000004');
insert into user(id, name, age, gender, phone) VALUES (null,'光明右使',48,'1','18800000005');
select * from user;
-- 部门管理
create table dept(
id int unsigned primary key auto_increment comment '主键ID',
name varchar(10) not null unique comment '部门名称',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '部门表';
insert into dept (id, name, create_time, update_time) values(1,'学工部',now(),now()),(2,'教研部',now(),now()),(3,'咨询部',now(),now()), (4,'就业部',now(),now()),(5,'人事部',now(),now());
-- 员工管理
create table emp (
id int unsigned primary key auto_increment comment 'ID',
username varchar(20) not null unique comment '用户名',
password varchar(32) default '123456' comment '密码',
name varchar(10) not null comment '姓名',
gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
image varchar(300) comment '图像',
job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
entrydate date comment '入职时间',
dept_id int unsigned comment '部门ID',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '员工表';
INSERT INTO emp(id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time) VALUES
(1,'jinyong','123456','金庸',1,'1.jpg',4,'2000-01-01',2,now(),now()),
(2,'zhangwuji','123456','张无忌',1,'2.jpg',2,'2015-01-01',2,now(),now()),
(3,'yangxiao','123456','杨逍',1,'3.jpg',2,'2008-05-01',2,now(),now()),
(4,'weiyixiao','123456','韦一笑',1,'4.jpg',2,'2007-01-01',2,now(),now()),
(5,'changyuchun','123456','常遇春',1,'5.jpg',2,'2012-12-05',2,now(),now()),
(6,'xiaozhao','123456','小昭',2,'6.jpg',3,'2013-09-05',1,now(),now()),
(7,'jixiaofu','123456','纪晓芙',2,'7.jpg',1,'2005-08-01',1,now(),now()),
(8,'zhouzhiruo','123456','周芷若',2,'8.jpg',1,'2014-11-09',1,now(),now()),
(9,'dingminjun','123456','丁敏君',2,'9.jpg',1,'2011-03-11',1,now(),now()),
(10,'zhaomin','123456','赵敏',2,'10.jpg',1,'2013-09-05',1,now(),now()),
(11,'luzhangke','123456','鹿杖客',1,'11.jpg',5,'2007-02-01',3,now(),now()),
(12,'hebiweng','123456','鹤笔翁',1,'12.jpg',5,'2008-08-18',3,now(),now()),
(13,'fangdongbai','123456','方东白',1,'13.jpg',5,'2012-11-01',3,now(),now()),
(14,'zhangsanfeng','123456','张三丰',1,'14.jpg',2,'2002-08-01',2,now(),now()),
(15,'yulianzhou','123456','俞莲舟',1,'15.jpg',2,'2011-05-01',2,now(),now()),
(16,'songyuanqiao','123456','宋远桥',1,'16.jpg',2,'2010-01-01',2,now(),now()),
(17,'chenyouliang','123456','陈友谅',1,'17.jpg',NULL,'2015-03-21',NULL,now(),now());
src/main/java/minm/mapper/EmpMapper.java
package minm.mapper;
import minm.pojo.Emp;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDate;
import java.util.List;
/**
* @author minm
* @version 1.0
* @description: TODO
* @date 2024/4/29 下午6:01
*/
@Mapper
public interface EmpMapper {
//根据ID删除数据
@Delete("delete from emp where id = #{id}")
public void delete(Integer id);
//public int delete(Integer id);
//新增员工
@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);
//更新员工
@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);
//方案三: 开启mybatis的驼峰命名自动映射开关 --- a_cloumn ------> aColumn
//根据ID查询员工
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
//方案一: 给字段起别名, 让别名与实体类属性一致
//@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);
//方案二: 通过@Results, @Result注解手动映射封装
//@Results({
// @Result(column = "dept_id", property = "deptId"),
// @Result(column = "create_time", property = "createTime"),
// @Result(column = "update_time", property = "updateTime")
//})
//@Select("select * from emp where id = #{id}")
//public Emp getById(Integer id);
//条件查询员工
//方式一
//@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(String name, Short gender, LocalDate begin , LocalDate end);
//方式二
// @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(String name, Short gender, LocalDate begin , LocalDate end);
//动态条件查询
public List<Emp> list(String name, Short gender, LocalDate begin , LocalDate end);
//动态更新员工
public void update2(Emp emp);
//批量删除员工
public void deleteByIds(List<Integer> ids);
}
src/main/java/minm/pojo/Emp.java
package minm.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* @author minm
* @version 1.0
* @description: TODO
* @date 2024/4/29 下午5:58
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
private Integer id; //ID
private String username; //用户名
private String password; //密码
private String name; //姓名
private Short gender; //性别, 1 男, 2 女
private String image; //图像url
private Short job; //职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师'
private LocalDate entrydate; //入职日期
private Integer deptId; //部门ID
private LocalDateTime createTime; //创建时间
private LocalDateTime updateTime; //修改时间
}
src/main/resources/application.properties
spring.application.name=springboot-mybatis-crud
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=21MINM
#配置mybatis的日志, 指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#开启mybatis的驼峰命名自动映射开关 a_column ------> aCloumn
mybatis.configuration.map-underscore-to-camel-case=true
编写测试案例测试
src/test/java/minm/SpringbootMybatisCrudApplicationTests.java
@SpringBootTest
class SpringbootMybatisCrudApplicationTests {
@Autowired
private EmpMapper empMapper;
@Test
public void testDelete() {
Integer i = empMapper.delete(17);
System.out.println(i);
}
}
/**
*==> Preparing: delete from emp where id = ? 预编译sql
* ==> Parameters: 17(Integer)
* <== Updates: 1
*/
预编译SQL
优势
- 性能更高
- 更安全(防止SQL注入)
SQL注入
- SQL注入是通过操作输入的数据来修饰实现定义好的SQL语句,以达到执行代码对服务器进行攻击的方式
文件名称: sql注入案例 分享链接:https://wwf.lanzn.com/b00rn10qpe 提取码:gv1y 分享有效时间: 永久
sql注入演示>java -jar sql_Injection_demo-0.0.1-SNAPSHOT.jar
jar包中默认数据库密码为1234
在IDEA上可以用反编译插件安装 File Expander 插件 反编译jar包进行修改
或者
在jar包所在的路径打开cmd窗口/Powershell窗口
方法是:进入jar包所在的路径,按住shift同时点击右键,选择“打开PowerShell窗口”;
列出jar包的文件清单(非必须,主要是为了方便查看需要修改的文件的路径)
//输入命令
jar tf abc.jar
将需要修改的文件解压出来
//命令
jar xf abc.jar BOOT-INF/classes/application.properties
此时,会在当前jar包的同级目录下生成一个相对路径文件夹(所要修改的文件就在这里),然后修改文件中的内容
使用修改后的文件替换jar包中对应的文件
//使用刚刚修改的文件替换jar包中的对应文件,输入命令
jar uf abc.jar BOOT-INF/classes/application.properties
以上是解压相对的文件,修改内容,再替换掉jar中的对应文件。
运行jar包
java -jar sql_Injection_demo-0.0.1-SNAPSHOT.jar
在游览器中输入http://localhost:9090/login.html
日志记录为
结果永远为真
java -jar sql_prepared_demo-0.0.1-SNAPSHOT.jar
日志结果为
参数占位符
#{...}
- 执行SQL时,会将#{...}替换为?,生成预编译SQL,会自动设置参数值。
- 使用时机:参数传递,都使用#
${...}
- 拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入的问题。
- 使用时机:如果对表名、列表进行动态设置时使用。
数据封装
- 实体类属性名 和 数据库表查询返回得字段名一致,mybatis回自动封装。
- 如果实体类属性名 和数据库表查询返回得字段名不一致,不能自动封装。
解决方法
- 起别名:在SQL语句中,对不一样的列明起别名,别名和实体类属性名一样。
点击查看代码
@Select("select id,username,password,name,gender,image,job,entrydate,dept_id deptID,crerte_time createTime,update_time updateTime from emp where id = #{id}")
public Emp getById(Integer id);
- 手动结果隐射:通过@Resulte及@Result进行手动结果隐射。
点击查看代码
@Select("select * from emp where id = #{id}")
@Results({
@Result(column = "dept_id",property="deptId"),
@Result(column = "create_time",property="createTime"),
@Result(column = "uodate_time",property="updateTime"),
})
public Emp getBuId(Integer id);
- 开启驼峰命名:如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射
点击查看代码
#开启驼峰命名自动隐射,即从数据库字段名a_column映射到java属性名aColumn。
mybatis.configuration.map-underscore-to-camel-case=true
条件查询
XML映射文件
规范
-
XML映射文件的名称与Mapper接口名称一直,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
-
XML映射文件的namespace属性为Mapper接口全限定名一致
-
XML隐射文件中sql语句id与Mapper接口中方法名一致,并保持返回类型一致。
可以安装MybatisX插件,快速开发。
动态SQL
随着用户的输入和外部条件的变化而变化的SQL语句,我们成为动态SQL
<if>
- <if>:用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL
foreach标签
sql-和-include
写sql片段,id和include的refid一样
<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="minm.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>
本文来自博客园,作者:21MINM,转载请注明原文链接:https://www.cnblogs.com/21MINM/p/18162757