【JavaEE 进阶(六)】Mybatis操作数据库

❣博主主页: 33的博客

▶️文章专栏分类:JavaEE◀️

🚚我的代码仓库: 33的代码仓库🚚

🫵🫵🫵关注我带你了解更多进阶知识

目录

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,更新操作:返回更新的数据量
  • 处理结果集
  • 释放资源
java 复制代码
//创建数据库
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具体代码(以新增为例)

java 复制代码
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文件中导入相关依赖。

数据准备:

sql 复制代码
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' );

对应实体类:
与表中字段名一致

java 复制代码
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配置数据库连接

java 复制代码
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写持久层代码

java 复制代码
@Mapper
public interface UserInfoMapper {
 //查询所有⽤⼾
 @Select("select username, `password`, age, gender, phone from userinfo")
 public List<UserInfo> queryAllUser();
}

进行单元测试,自动生成

java 复制代码
@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语句的执⾏、执⾏传递的参数以及执⾏结果在配置⽂件中进⾏配置即可:

java 复制代码
mybatis:
 configuration: # 配置打印 MyBatis⽇志
   log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.2.2参数传递

如果要查找id为4的用户信息可以写为:

java 复制代码
@Select("select username, `password`, age, gender, phone from userinfo where id= 4 ")
UserInfo queryById();

但是这样就把id写死了,不能修改,那么我们可以使用参数来优化:

java 复制代码
@Select("select username, `password`, age, gender, phone from userinfo where id= #{id} ")
UserInfo queryById(Integer id);

当我们调用queryById时,传递不同的id值就可以查询出不同的信息。

3.2.3增

java 复制代码
@Insert("insert into userinfo (username, `password`, age, gender, phone) values (#{username},#{password},#{age},#{gender},#{phone})")
Integer insert(UserInfo userInfo);

测试:

java 复制代码
@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删

java 复制代码
@Delete("delete from userinfo where id = #{id}")
void delete(Integer id);

测试

java 复制代码
@Test
void delete() {
 userInfoMapper.delete(4);
}

3.2.4改

java 复制代码
@Update("update userinfo set username=#{username} where id=#{id}")
void update(UserInfo userInfo);

测试

java 复制代码
@Test
void  update() {
 UserInfo userInfo = new UserInfo();
 userInfo.setUsername("zhaoliu666");
 userInfo.setId(5);
 userInfoMapper.insert(userInfo);
}

3.2.5查

java 复制代码
@Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo")
List<UserInfo> queryAllUser();

测试

java 复制代码
@Test
void  queryAllUser() {;
 userInfoMapper.queryAllUser();
}

当我们查询的时候,我们发现有一些数值为空,但数据库中却有值是怎么回事呢?

MyBatis会根据方法的返回结果进行赋值,方法用对象UserInfo接收结果,就会根据对应UserInfo的属性进行赋值。

解决办法:

1.起别名

java 复制代码
@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.结果映射

java 复制代码
@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.开启驼峰命名

java 复制代码
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结尾的文件

java 复制代码
mybatis:
 mapper-locations: classpath:mapper/**Mapper.xml

3.3.2Mapper接口

mapper文件种添加UserInfoXMlMapper类

java 复制代码
@Mapper
public interface UserInfoXMlMapper {
 List<UserInfo> queryAllUser();
}

resources/mapper创建UserInfoXMLMapper.xml类,并添加XML固定格式

java 复制代码
<?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增

java 复制代码
Integer insertUser(UserInfo userInfo);
java 复制代码
<insert id="insertUser">
insert into userinfo (username, `password`, age, gender, phone) values (#{username}, #{password}, #{age},#{gender},#{phone})
</insert>

3.3.4删

java 复制代码
Integer deleteUser(Integer id);
java 复制代码
<delete id="deleteUser">
 delete from userinfo where id = #{id}
</delete>

3.3.5改

java 复制代码
Integer updateUser(UserInfo userInfo);
java 复制代码
<update id="updateUser">
 update userinfo set username=#{username} where id=#{id}
</update>

3.3.6查

java 复制代码
List<UserInfo> queryAllUser();
java 复制代码
<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>

#{}和${}区别

java 复制代码
@Select("select username, `password`, age, gender, phone from userinfo where username= ${name} ")
UserInfo queryByName(String name);

运行结果:

使用${}是直接进行字符串拼接,但是字符串作为参数时,需要添加' ',使用 ${}不会拼接' '。

解决

java 复制代码
@Select("select username, `password`, age, gender, phone from userinfo where username= '${name}' ")
UserInfo queryByName(String name);

#{}与${}区别

1.性能更高

2.更安全(防止SQL注入)

java 复制代码
@Select("select username, `password`, age, gender, phone from userinfo where username= '${name}' ")
List<UserInfo> queryByName(String name);

正常情况下:

java 复制代码
@Test
void queryByName() {
 List<UserInfo> userInfos = userInfoMapper.queryByName("admin");
 System.out.println(userInfos);
 }
}

sql注入:

java 复制代码
@Test
void queryByName() {
 List<UserInfo> userInfos = userInfoMapper.queryByName("' or 1='1");
 System.out.println(userInfos);
}

这时结果依然被正确查询出来了, 其中参数 or被当做了SQL语句的⼀部分。这时就会查询出所有的表中数据。

既然${}会有Sql注入的风险,那么它是否就没有用呢?实现排序,like查询的时候只能使用 ${}不能使用#{},例如:

java 复制代码
@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归还给连接池

优点:

  1. 减少了⽹络开销
  2. 资源重⽤
  3. 提升了系统的性能

5.总结

利用MyBatis进行数据库的增删改查操作,使用驼峰转换时,要注意java中的属性和数据库中属性的对应关系,一般创建数据库时,表必备三字段: id, create_time, update_time,在表查询中, 避免使⽤ * 作为查询的字段列表, 标明需要哪些字段。

下期预告:MyBatis进阶

相关推荐
Elastic 中国社区官方博客34 分钟前
使用 Elasticsearch 导航检索增强生成图表
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
小金的学习笔记38 分钟前
RedisTemplate和Redisson的使用和区别
数据库·redis·缓存
新知图书1 小时前
MySQL用户授权、收回权限与查看权限
数据库·mysql·安全
文城5211 小时前
Mysql存储过程(学习自用)
数据库·学习·mysql
沉默的煎蛋1 小时前
MyBatis 注解开发详解
java·数据库·mysql·算法·mybatis
呼啦啦啦啦啦啦啦啦1 小时前
【Redis】事务
数据库·redis·缓存
HaoHao_0101 小时前
AWS Serverless Application Repository
服务器·数据库·云计算·aws·云服务器
C语言扫地僧1 小时前
MySQL 事务及MVCC机制详解
数据库·mysql
小镇cxy1 小时前
MySQL事物,MVCC机制
数据库·mysql
书生-w2 小时前
Redis Windows 解压版安装
数据库·windows·redis