❣博主主页: 33的博客❣
▶️文章专栏分类:JavaEE◀️
🚚我的代码仓库: 33的代码仓库🚚
🫵🫵🫵关注我带你了解更多进阶知识
目录
- 1.前言
- 2.JDBC操作
- 3.Mybatis
- 3.1Mybatis入门
- 3.1.1准备工作
- 3.1.2配置数据库连接
- 3.1.2写持久层代码
- 3.2MyBatis基础操作
- 3.2.1打印日志
- 3.2.2参数传递
- 3.2.3增
- 3.2.3删
- 3.2.4改
- 3.2.5查
- 3.3MyBatis XML配置
- 3.3.1配置XML文件
- 3.3.2Mapper接口
- 3.3.3增
- 3.3.4删
- 3.3.5改
- 3.3.6查
- #{}和${}区别
- 4.数据库连接池
- 5.总结
1.前言
在应用分层学习时,我们了解到web应⽤程序⼀般分为三层,即:Controller、Service、Dao。之前的案例中,请求流程如下:浏览器发起请求,先请求Controller,Controller接收到请求之后,调用Service进⾏业务逻辑处理,Service再调⽤Dao,但是Dao层的数据是Mock的,真实的数据应该从数据库中读取。我们知道在java中可以通过JDBC来操作数据库,但这样操作是非常复杂的,那在Spring Boot中有更简便的方法吗?接下来我们就进行学习吧!
2.JDBC操作
我们先了解一下通过JDBC来操作数据库:
- 创建数据库连接池DataSource
- 通过数据库连接池获取数据库连接Connection
- 编写带有?占位符的sql语句
- 替换占位符,指定要替换的数据库字段类型,要替换的值。
- 使用Statement执行SQL语句
- 查询操作:返回结果ResultSet,更新操作:返回更新的数据量
- 处理结果集
- 释放资源
//创建数据库
create database if not exists library default character set utf8mb4;
use library;--
//创建表
create table if not exists soft_bookrack (
book_name varchar(32) NOT NULL,
book_author varchar(32) NOT NULL,
book_isbn varchar(32) NOT NULL primary key
);
JDBC具体代码(以新增为例)
public class SimpleJdbcOperation {
private final DataSource dataSource;
public SimpleJdbcOperation(DataSource dataSource) {
this.dataSource = dataSource;
}
//添加⼀本书
public void addBook() {
Connection connection = null;
PreparedStatement stmt = null;
try {
//获取数据库连接
connection=dataSource.getConnection();
//创建语句
stmt=connection.prepareStatement("insert into soft_bookrack (book_name, book_author, book_isbn) values (?,?,?);");
//参数绑定
stmt.setString(1, "Spring in Action");
stmt.setString(2, "Craig Walls");
stmt.setString(3, "9787115417305");
//执⾏语句
stmt.execute();
} catch (SQLException e) {
//处理异常信息
} finally {
//清理资源
try {
if (stmt != null) {
stmt.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
//
}
}
}
从上诉代码可见,对于JDBC来说,整个操作是非常麻烦的,,我们不但要拼接每⼀个参
数,而且还要按照模板代码的⽅式,⼀步步的操作数据库,并且在每次操作完,还要⼿动关闭连接等,而所有的这些操作步骤都需要在每个⽅法中重复书写.那有没有⼀种方法,可以更简单、更方便的操作数据库呢?当然是有的,那就是Mybatis,它可以帮助我们更方便的操作数据库。
3.Mybatis
Mybatis是持久层框架,用于简化JDBC的开发。持久层就是指持久化操作的层,通常指数据访问层,用来操作数据库的。
简单来说Mybatis是更简单完成程序和数据库交互的框架。
3.1Mybatis入门
3.1.1准备工作
创建Spring boot工程,并导入mybatis的依赖和mysql驱动包
项目创建完成之后,会自动在pom文件中导入相关依赖。
数据准备:
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
USE mybatis_test;
CREATE TABLE `userinfo` (
`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
`username` VARCHAR ( 127 ) NOT NULL,
`password` VARCHAR ( 127 ) NOT NULL,
`age` TINYINT ( 4 ) NOT NULL,
`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认',
`phone` VARCHAR ( 15 ) DEFAULT NULL,
`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
`create_time` DATETIME DEFAULT now(),
`update_time` DATETIME DEFAULT now(),
PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
//添加⽤⼾信息
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
对应实体类:
与表中字段名一致
import lombok.Data;
import java.util.Date;
@Data
public class UserInfo {
private Integer id;
private String username;
private String password;
private Integer age;
private Integer gender;
private String phone;
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
}
3.1.2配置数据库连接
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?
characterEncoding=utf8&useSSL=false
username: root//用户名
password: root//密码
driver-class-name: com.mysql.cj.jdbc.Driver
3.1.2写持久层代码
@Mapper
public interface UserInfoMapper {
//查询所有⽤⼾
@Select("select username, `password`, age, gender, phone from userinfo")
public List<UserInfo> queryAllUser();
}
进行单元测试,自动生成
@SpringBootTest
class UserInfoMapperTest {
@Autowired
private UserInfoMapper userInfoMapper;
@Test
void queryAllUser() {
List<UserInfo> userInfoList = userInfoMapper.queryAllUser();
System.out.println(userInfoList);
}
}
3.2MyBatis基础操作
3.2.1打印日志
在Mybatis当中我们可以借助⽇志, 查看到sql语句的执⾏、执⾏传递的参数以及执⾏结果在配置⽂件中进⾏配置即可:
mybatis:
configuration: # 配置打印 MyBatis⽇志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3.2.2参数传递
如果要查找id为4的用户信息可以写为:
@Select("select username, `password`, age, gender, phone from userinfo where id= 4 ")
UserInfo queryById();
但是这样就把id写死了,不能修改,那么我们可以使用参数来优化:
@Select("select username, `password`, age, gender, phone from userinfo where id= #{id} ")
UserInfo queryById(Integer id);
当我们调用queryById时,传递不同的id值就可以查询出不同的信息。
3.2.3增
@Insert("insert into userinfo (username, `password`, age, gender, phone) values (#{username},#{password},#{age},#{gender},#{phone})")
Integer insert(UserInfo userInfo);
测试:
@Test
void insert() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("zhaoliu");
userInfo.setPassword("zhaoliu");
userInfo.setGender(2);
userInfo.setAge(21);
userInfo.setPhone("18612340005");
userInfoMapper.insert(userInfo);
}
3.2.3删
@Delete("delete from userinfo where id = #{id}")
void delete(Integer id);
测试
@Test
void delete() {
userInfoMapper.delete(4);
}
3.2.4改
@Update("update userinfo set username=#{username} where id=#{id}")
void update(UserInfo userInfo);
测试
@Test
void update() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("zhaoliu666");
userInfo.setId(5);
userInfoMapper.insert(userInfo);
}
3.2.5查
@Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo")
List<UserInfo> queryAllUser();
测试
@Test
void queryAllUser() {;
userInfoMapper.queryAllUser();
}
当我们查询的时候,我们发现有一些数值为空,但数据库中却有值是怎么回事呢?
MyBatis会根据方法的返回结果进行赋值,方法用对象UserInfo接收结果,就会根据对应UserInfo的属性进行赋值。
解决办法:
1.起别名
@Select("select id, username, `password`, age, gender, phone, delete_flag as deleteFlag, create_time as createTime, update_time as updateTime from userinfo")
public List<UserInfo> queryAllUser();
2.结果映射
@Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo")
@Results({
@Result(column = "delete_flag",property = "deleteFlag"),
@Result(column = "create_time",property = "createTime"),
@Result(column = "update_time",property = "updateTime")
})
List<UserInfo> queryAllUser();
3.开启驼峰命名
mybatis:
configuration:
map-underscore-to-camel-case: true #配置驼峰⾃动转换
此时代码不用做任何处理,会把update_time转换为:updateTime并赋值
3.3MyBatis XML配置
MyBatis的开发方式有2种,注解和XML上面我们学习的都是通过注解实现的,接下来我们通过XML来实现。
3.3.1配置XML文件
配置XML文件路径,在resources/mapper下面,以Mapper.xml结尾的文件
mybatis:
mapper-locations: classpath:mapper/**Mapper.xml
3.3.2Mapper接口
mapper文件种添加UserInfoXMlMapper类
@Mapper
public interface UserInfoXMlMapper {
List<UserInfo> queryAllUser();
}
resources/mapper创建UserInfoXMLMapper.xml类,并添加XML固定格式
<?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="com.example.demo.mapper.UserInfoMapper">
<select id="queryAllUser" resultType="com.example.demo.model.UserInfo">
select username,`password`, age, gender, phone from userinfo
</select>
</mapper>
3.3.3增
Integer insertUser(UserInfo userInfo);
<insert id="insertUser">
insert into userinfo (username, `password`, age, gender, phone) values (#{username}, #{password}, #{age},#{gender},#{phone})
</insert>
3.3.4删
Integer deleteUser(Integer id);
<delete id="deleteUser">
delete from userinfo where id = #{id}
</delete>
3.3.5改
Integer updateUser(UserInfo userInfo);
<update id="updateUser">
update userinfo set username=#{username} where id=#{id}
</update>
3.3.6查
List<UserInfo> queryAllUser();
<select id="queryAllUser" resultType="com.example.demo.model.UserInfo">
select id, username,`password`, age, gender, phone, delete_flag,
create_time, update_time from userinfo
</select>
#{}和${}区别
@Select("select username, `password`, age, gender, phone from userinfo where username= ${name} ")
UserInfo queryByName(String name);
运行结果:
使用${}是直接进行字符串拼接,但是字符串作为参数时,需要添加’ ‘,使用 ${}不会拼接’ '。
解决
@Select("select username, `password`, age, gender, phone from userinfo where username= '${name}' ")
UserInfo queryByName(String name);
#{}与${}区别
1.性能更高
2.更安全(防止SQL注入)
@Select("select username, `password`, age, gender, phone from userinfo where username= '${name}' ")
List<UserInfo> queryByName(String name);
正常情况下:
@Test
void queryByName() {
List<UserInfo> userInfos = userInfoMapper.queryByName("admin");
System.out.println(userInfos);
}
}
sql注入:
@Test
void queryByName() {
List<UserInfo> userInfos = userInfoMapper.queryByName("' or 1='1");
System.out.println(userInfos);
}
这时结果依然被正确查询出来了, 其中参数 or被当做了SQL语句的⼀部分。这时就会查询出所有的表中数据。
既然${}会有Sql注入的风险,那么它是否就没有用呢?实现排序,like查询的时候只能使用 ${}不能使用#{},例如:
@Select("select id, username, age, gender, phone, delete_flag, create_time, update_time " +"from userinfo order by id ${sort} ")
List<UserInfo> queryAllUserBySort(String sort);
这时候传入的sort不需要引号所以必须要使用${}
4.数据库连接池
数据库连接池负责分配、管理和释放数据库连接,它允许应⽤程序重复使⽤⼀个现有的数据库连接,而不是再重新建⽴⼀个。
没有使用数据库连接池的情况: 每次执⾏SQL语句, 要先创建⼀个新的连接对象, 然后执⾏SQL语句, SQL语句执⾏完, 再关闭连接对象释放资源. 这种重复的创建连接, 销毁连接⽐较消耗资源
使用数据库连接池的情况: 程序启动时, 会在数据库连接池中创建⼀定数量的Connection对象, 当客⼾请求数据库连接池, 会从数据库连接池中获取Connection对象, 然后执⾏SQL, SQL语句执⾏完, 再把Connection归还给连接池
优点:
- 减少了⽹络开销
- 资源重⽤
- 提升了系统的性能
5.总结
利用MyBatis进行数据库的增删改查操作,使用驼峰转换时,要注意java中的属性和数据库中属性的对应关系,一般创建数据库时,表必备三字段: id, create_time, update_time,在表查询中, 避免使⽤ * 作为查询的字段列表, 标明需要哪些字段。
下期预告:MyBatis进阶