初始JavaEE篇 —— Mybatis操作数据库(上)

找往期文章包括但不限于本期文章中不懂的知识点:

个人主页: 我要学编程程(ಥ_ಥ)-CSDN博客

所属专栏: JavaEE

目录

前言

Mybatis快速入门

Mybatis的基础操作(注解实现接口类)

打印日志

查询

增加

删除

更新

XML实现接口类

快速上手

查询

增加

删除

更新

其他查询操作

多表查询

[#{} 和 {} 的区别](#{} 和 {} 的区别)

数据库连接池


前言

在MySQL的学习阶段,我们知道了如何使用JDBC去操作,也正是因为学习了JDBC也知道其操作的繁琐,每次的CRUD操作都需要从数据库连接池中去获取数据库连接,然后再编写SQL语句,并绑定对应的参数,接着通过连接执行SQL语句,如果返回值的话还得处理返回值,最后还得释放连接等资源。明明在增删改查阶段只需要修改SQL语句以及对应的参数和处理返回结果即可,但还是存在很多重复性的操作的。因此,Mybatis就由此而诞生了,Mybatis实现了对JDBC的进一步简化与封装,让Java开发者可以更加简单的去操作数据库。

Mybatis快速入门

Mybatis操作数据库的步骤:

1、准备工作(创建SpringBoot项目、数据库表的准备、Java实体类的准备)

2、引入Mybatis的相关依赖,配置Mybatis(数据库连接信息)

3、编写SQL语句(使用注解或者xml)

4、测试代码

File -> New -> Project:

选择相应的依赖:

检查pom文件依赖是否正确导入:

注意:SpringBoot依赖的大版本要和Mybatis依赖的大版本一致,由于我这里的SpringBoot项目使用的是 2.x ,因此 Mybatis的依赖版本也是 2.x。

接下来创建对应的数据表以及填充数据:

sql 复制代码
-- 创建数据库
drop database if exists mybatis_test;
create database mybatis_test; -- MySQL的版本是8.x无需指定字符集编码

use mybatis_test; -- 图形化界面中可省略

-- 创建数据表
drop table if exists user_info;
create table user_info (
  id bigint primary key auto_increment,
  username varchar(50) not null,
  password varchar(50) not null,
  age tinyint not null,
  gender bit(1) default 1 comment '1-男, 0-女',
  phone varchar(15) default null,
  delete_flag bit(1) default 0 comment '1-删除, 0-正常',
  create_time datetime default now(),
  update_time datetime default now()
);

-- 添加用户信息
insert into user_info (username, password, age, gender, phone) values
('admin', 'admin_123456', 20, 1, '0987654321'), 
('张三', 'zs_123456', 20, 1, '1234567890'),
('李四', 'ls_123456', 22, 1, '1234567809'),
('王五', 'ww_123456', 25, 1, '1234567980');

-- 查看数据表是否创建以及初始化正确
select * from user_info;

创建Java中对应的实体类:

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

配置数据库连接:

XML 复制代码
# 配置数据库连接
spring:
  datasource:
    # URL根据自己的实际情况配置,同样后续的 username 和 password 也是如此
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
#    driver-class-name: com.mysql.jdbc.Driver # 这是5.x版本及其之前使用的

接下来就是编写查询SQL了(先使用看看效果,后面再学习)

java 复制代码
@Mapper // 只能使用@Mapper注解
public interface UserInfoMapper { // 在mapper包下(属于数据层)
    @Select("select * from user_info")
    List<UserInfo> selectAll();
}

接着在UserInfoMapper这个类所在的文件中,右键找到Generate,点击 Test

按照上述步骤,就会生成一个测试类:

java 复制代码
@SpringBootTest // 加载spring的运行环境(为了DI)
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test // 标记该方法为测试方法,可以直接运行
    void selectAll() {
        List<UserInfo> userInfos = userInfoMapper.selectAll();
        System.out.println(userInfos);
    }
}

我们只需要在@Test注解的左侧点击run即可运行该方法(运行结果如下):

从上述步骤来看,从编写SQL语句到测试的步骤非常简单。 所以的一切都是spring帮我们做好了,我们只需要使用即可。

注意:

1、只有查询的SQL中对应的字段才会在对象对应的属性中有值。但细心的小伙伴可能会发现,删除标志、创建时间、更新时间 也同样没有值,这个我们后面再学习。

2、Mybatis也是一个框架,是独立于Spring框架的,Mybatis是对JDBC的封装,即JDBC在Maven项目中可以使用,同样Mybatis也能在Maven项目中使用。但要注意的是上面的依赖是只能在SpringBoot项目中使用,在Maven项目使用的依赖并不是长那样。

既然已经知道了Mybatis框架的优点,接下来就具体学习Mybatis是如何操作数据库的。

Mybatis的基础操作(注解实现接口类)

使用Mybatis操作数据库的话,我们都是创建一个mapper包用来存放具体的操作接口,然后在对应的接口中去编写方法。接着就只需要Mybatis来实现该接口方法,然后我们再将该接口类注册到Spring的容器中,使用容器来实现依赖注入,接着就是调用对应的操作方法即可。 Mybatis 实现 该接口方法的方式有两种:1、使用注解;2、使用xml。我们先来学习简单的注解。

打印日志

在Mybatis中,我们可以使用日志,来查看SQL语句的执行、参数的传递,以及执行的结果。因此我们需要先配置:

java 复制代码
# 配置Mybatis日志
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

重新启动程序,测试该查询方法,观察控制台的输出:

查询

如果我们想要查询数据库中的数据,只需要创建一个接口方法,并在上方加上@Select注解,里面加上查询的语句即可。

需求:查询id=1的用户

虽然上述方式能够查询id = 1的数据,但是这种方法是写死的,即通过手动指定来查询的数据,但在实际开发中,往往是需要动态的数值。这里就需要用到 "#{参数名}" 的方式了。

我们也可以观察日志,会发现存在传递的参数以及其类型了。那如果查询不存在的数据呢?

注意:

1、如果接口方法里面的形参只有一个时,#{参数名},这里的参数名可以是任意值。

2、如果想改名的话,需要通过@Param注解将修改后的参数名写入其中。

当然上述代码,即使不加上@Param注解也是可以成功运行的,毕竟这里只有一个形参。但是为了可读性,还是要保持两者的一致性。

如果方法有多个参数且未使用 @Param,MyBatis 默认通过 arg0arg1param1param2 引用参数。此时若直接使用 #{id}#{name} 会报错,需显式通过 @Param 命名参数。前面两种方式的可读性会很差,不推荐。但是有的情况下,即使不加上 @Param也是OK的。具体可参考下面的文章:

MyBatis多参数传递之@Param究竟加还是不加?_mybatis传递多个参数需要使用param注解?-CSDN博客

虽然我的JDK是1.8,但是IDEA配置中并未配置 parameters,因此我的代码在面对多参数时,必须要加上@Param。但我又创建了一个新项目(SpringBoot的版本是3.x),打开却发现IDEA自动配置了,所以我个人猜测可能是SpringBoot的版本不同,导致的结果。但还是需要将@Param加上,预防特殊的情况。

接下来,解决查询的对象中关于时间的部分并未赋值的问题:之所以出现这种并未赋值的现象,是因为数据库中的字段和Java实体类中的属性,两者的名称不是一致(忽略大小写)的,因此并不会对其进行赋值。也就是说只有当数据库的字段和Java实体类中的属性完全一致(忽略大小写)时,Mybatis才可以帮助我们进行自动赋值。这里的解决方法有三种:1、起别名;2、结果映射;3、使用驼峰命名。

起别名

结果映射

通过@Results注解、@Result注解、@ResultMap注解 来实现数据库字段与Java实体类属性之间的映射以及后续的复用问题。

将数据库字段映射到Java实体类的属性上。

使用驼峰命名

通过设置配置文件,来自动绑定数据库字段的蛇形命名和Java实体类属性的驼峰命名。

java 复制代码
mybatis:
  configuration:
    map-underscore-to-camel-case: true # 配置驼峰自动转换

3、查询的返回的结果一定是要能存放在接口方法返回值的"容器"中的。这里的容器并不是我们在数据结构阶段学习的集合,范围要更大一些。例如,根据id来查询数据时,返回的是一个UserInfo对象,我们可以使用List来接收,也可以使用UserInfo对象本身来接收,但是如果返回的是多条数据,这时就只能使用List来接收了,一个UserInfo对象存不下。如果执意使用UserInfo对象来接收的话,最终就会报错。

4、当查询的参数变得很多时,如果我们还是采用手写的话,代码就会显得特别臃肿。解决方法是采用传输对象的方式。

增加

增加数据,是通过@Insert注解实现的,只需要在里面加上对应的SQL语句即可。

上述这种方式是比较繁琐的,我们可以使用传输对象的方式:

Insert语句默认返回的是受影响的行数,但在有些情景下,数据插入之后,需要获取的新插入的数据的id,提供给后续的操作。例如,订单系统的中的下完订单之后,后续的物流系统、库存系统等都需要拿到订单的id来进行操作。如果想要拿到自增的id,需要在接口方法上添加Options注解。

获取自动生成的主键值:通过Options注解来获取,其属性useGeneratedKeys=true表示使用数据库自增主键,keyColumn用于指定数据库table中的主键,keyProperty用于指定传入对象的属性(绑定到对象的哪个属性)。如果我们已经在数据库表中指定了主键,并且数据库中主键的名称和Java属性的名称是相同的,那么keyColumn属性可以省略。

当数据库的字段为bigint,而实体类的属性为Integer类型时,类型转换会失效。因为bigint在Java中对应的是Long类型,因此要么将数据库的字段属性修改,要么将实体类的属性修改。如果数据库的字段声明为bigint unsigned 的话,实体类的属性就需要修改为BigInteger了。

删除

删除数据,是通过@Delete注解实现的,只需要在里面加上对应的SQL语句即可。

我们通过结果可以观察的到,从最初的6条数据变为了5条数据。

更新

更新数据,是通过@Update注解实现的,只需要在里面加上对应的SQL语句即可。

上面这种传参方式也是比较繁琐的,可以直接传输对象。

上述是使用注解的方式来实现接口接口方法的,除此之外,我们还可以使用xml来实现接口方法。

XML实现接口类

快速上手

配置数据源和导入依赖与前面是一样的。下面是不一样的配置:

1、配置 Mybatis 的 xml文件路径

java 复制代码
mybatis: # classpath 表示resources目录下,整体表示的是 resources/mapper/所有xml文件
         # * 代表通配符,表示只要是 .xml 文件即可
  mapper-locations: classpath:mapper/*.xml

第二步同样还是创建接口类,第三步不再是通过注解来实现SQL语句了,而是通过在配置的XML文件目录下创建XML文件,在文件中编写对应的实现SQL语句。

在新创建的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">
<!-- namespace 表示的该xml文件实现的接口类的全限定名称 -->
<mapper namespace="">

</mapper>

这里的namespace的值就是UserInfoMapperXML文件的全限定类名。

这里再介绍一个插件: mybatisx,

找到 File -> settings -> plugins -> 在marketplace中搜索 mybatisx,点击Install即可

安装该插件之后,会有两个好处:

1、知道XML文件中的mapper标签的namespace值是否绑定正确。如果绑定正确的话,对应的文件位置就会出现小鸟图标,点击该图标可以在绑定的文件之中任意跳转。

2、插件会自动校验对应的接口类的接口方法是否生成了对应的实现标签。如果生成对应的实现标签的话,就会在对应的标签和方法之间生成小鸟图标,同样可以实现自动跳转,反之,如果没有生成的话,就会在对应的接口类所在的方法上爆红。

XML 复制代码
<!-- 
select标签表示对应的接口类的方法是查询方法
id 表示该标签实现的方法名,resultType 表示返回的基本元素全限定类名
例如,返回List,里面的元素就是UserInfo,对应的值就是UserInfo的全限定类名
-->
<select id="selectAll" resultType="com.springboot.mybatisdemo2.pojo.UserInfo">
    <!-- 这里编写对应的SQL语句 -->
</select>

接下来,就可以在标签中编写对应的SQL语句了。

XML 复制代码
<select id="selectAll" resultType="com.springboot.mybatisdemo2.pojo.UserInfo">
    select * from user_info;
</select>

最后就是测试对应的SQL语句了,同样在接口类中,鼠标右键 -> Generate -> Test:

最后再编写测试代码,点击run即可看到查询SQL的结果。

java 复制代码
@SpringBootTest
class UserInfoMapperXMLTest {

    @Autowired
    private UserInfoMapperXML userInfoMapperXML;

    @Test
    void selectAll() {
        userInfoMapperXML.selectAll().forEach(System.out::println);
    }
}

查询

根据id查询:

根据 username 和 password 查询:

java 复制代码
// 根据username和password查询
UserInfo selectByUsernameAndPassword(String username, String password);

// 根据username和password查询
UserInfo selectByUsernameAndPassword(String username, String password);

@Test
void selectByUsernameAndPassword() {
    System.out.println(userInfoMapperXML.selectByUsernameAndPassword("admin", "admin_123456"));
}

根据 对象 来查询:

java 复制代码
// 根据对象来查询
UserInfo selectByUserInfo(UserInfo userInfo);

<select id="selectByUserInfo" resultType="com.springboot.mybatisdemo2.pojo.UserInfo">
    <!-- 注意,这里#{}内部的是实体类的属性名,其余的都是数据库的字段 -->
    select * from user_info where username = #{username} and password = #{password}
</select>

@Test
void selectByUserInfo() {
    UserInfo userInfo = new UserInfo();
    userInfo.setUsername("admin");
    userInfo.setPassword("admin_123456");
    System.out.println(userInfoMapperXML.selectByUserInfo(userInfo));
}

由于之前在配置文件中,设置过了驼峰自动转换,因此这里并不会出现对象属性为null的情况。现在我们来看在XML文件中,使用起别名和result标签如何解决。

XML 复制代码
<!-- 起别名 -->
<select id="selectAll2" resultType="com.springboot.mybatisdemo2.pojo.UserInfo">
    select id, username, password, age, gender, phone,
           delete_flag as deleteFlag,
           create_time as createTime,
           update_time as updateTime  from user_info
</select>



<!-- id是给别的标签使用所引用的  type表示映射到哪个实体类上 -->
<resultMap id="resultMap" type="com.springboot.mybatisdemo2.pojo.UserInfo">
    <!-- 规范的写法是要将数据表中所有字段和实体类的属性相对应的,
             即使有些字段和属性是对应上的,也最好要加上,因为是规范
             id 表示主键,result表示普通字段
        -->
    <id column="id" property="id"/>
    <result column="username" property="username"/>
    <result column="password" property="password"/>
    <result column="age" property="age"/>
    <result column="gender" property="gender"/>
    <result column="phone" property="phone"/>
    <result column="delete_flag" property="deleteFlag"/>
    <result column="create_time" property="createTime"/>
    <result column="update_time" property="updateTime"/>
</resultMap>

<!-- resultMap表示要引用的映射关系 -->
<select id="selectAll3" resultType="com.springboot.mybatisdemo2.pojo.UserInfo" resultMap="resultMap">
	select * from user_info
</select>

增加

新增数据,传递参数:

java 复制代码
// 新增数据:传递参数
Integer insertByUsernameAndPassword(String username, String password);

<insert id="insertByUsernameAndPassword">
    insert into user_info (username, password) values (#{username}, #{password})
</insert>

@Test
void insertByUsernameAndPassword() {
    System.out.println(userInfoMapperXML.insertByUsernameAndPassword("444", "444"));
}

新增数据,传递对象:

java 复制代码
// 新增数据:传递对象
Integer insertByUserInfo(UserInfo userInfo);

<insert id="insertByUserInfo">
    insert into user_info (username, password) values (#{username}, #{password})
</insert>

@Test
void insertByUserInfo() {
    UserInfo userInfo = new UserInfo();
    userInfo.setUsername("444");
    userInfo.setPassword("444");
    System.out.println(userInfoMapperXML.insertByUserInfo(userInfo));
}

新增数据,获取自增id:

java 复制代码
// 新增数据:获取自增的id
Integer insertGetGeneratedKey(UserInfo userInfo);

<insert id="insertGetGeneratedKey" useGeneratedKeys="true" keyProperty="id">
    insert into user_info (username, password) values (#{username}, #{password})
</insert>

@Test
void insertGetGeneratedKey() {
    UserInfo userInfo = new UserInfo();
    userInfo.setUsername("444");
    userInfo.setPassword("444");
    System.out.println("受影响的行数: " + userInfoMapperXML.insertGetGeneratedKey(userInfo));
    System.out.println("获取自增的id: " + userInfo.getId());
}

要确保 id 的类型是 Long,这样才能正确接收到。

删除

删除数据,传递id:

java 复制代码
// 删除数据:传递参数
Integer deleteById(Integer id);

<delete id="deleteById">
    delete from user_info where id = #{id}
</delete>

@Test
void deleteById() {
    System.out.println(userInfoMapperXML.deleteById(40));
}

删除数据,传递对象:

java 复制代码
// 删除数据:传递对象
Integer deleteByUserInfo(UserInfo userInfo);

<delete id="deleteByUserInfo">
    delete from user_info where username = #{username} and password = #{password}
</delete>

@Test
void deleteByUserInfo() {
    UserInfo userInfo = new UserInfo();
    userInfo.setUsername("admin");
    userInfo.setPassword("admin");
    System.out.println(userInfoMapperXML.deleteByUserInfo(userInfo));
}

更新

更新数据,传递参数

java 复制代码
// 更新数据:传递参数
Integer updateByUsernameAndPassword(Long id, String username, String password);

<update id="updateByUsernameAndPassword">
    update user_info set username = #{username}, password = #{password} where id = #{id}
</update>

@Test
void updateByUsernameAndPassword() {
    System.out.println(userInfoMapperXML.updateByUsernameAndPassword(33 L, "admin", "admin"));
}

更新数据,传递对象:

java 复制代码
// 更新数据:传递对象
Integer updateByUserInfo(UserInfo userInfo);

<update id="updateByUserInfo">
    update user_info set username = #{username}, password = #{password} where id = #{id}
</update>

@Test
void updateByUserInfo() {
    UserInfo userInfo = new UserInfo();
    userInfo.setId(32 L);
    userInfo.setUsername("admin");
    userInfo.setPassword("admin");
    System.out.println(userInfoMapperXML.updateByUserInfo(userInfo));
}

我们仔细观察会发现,除了select标签之外,其余的标签都没有resultType属性,这是因为只有select才会返回对应的数据行,其余的返回的都是受影响的行数。

其他查询操作

多表查询

数据表:

sql 复制代码
-- 删除文章表
drop table if exists article_info;

-- 创建文章表
create table if not exists article_info (
    id bigint primary key auto_increment,
    title varchar(256) not null,
    content text not null,
    user_id bigint not null,
    delete_flag bit(1) default 0 comment '0-正常,1-删除',
    create_time datetime default now(),
    update_time datetime default now()
);

-- 插入数据
insert into article_info (title, content, user_id) values ('Mybatis入门','Mybatis入门...',1);

-- 查询数据
select * from article_info;

对应的model类:

java 复制代码
@Data
public class ArticleInfo {
    // id、userId 要使用Long类型
    private Long id;
    private String title;
    private String content;
    private Long userId;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

对应的接口类,以及XML文件:

java 复制代码
@Mapper
public interface ArticleInfoMapper {
    // 根据userId查询作者的相关信息
    List<ArticleInfo> selectByUserId(Integer userId);
}

<select id="selectByUserId" resultType="com.springboot.mybatisdemo2.pojo.ArticleInfo">
    <!-- 这里也可以采取右连接的方式 -->
   select ta.*, tb.username, tb.age, tb.password from article_info ta
   left join user_info tb on ta.id = #{id} where ta.user_id = tb.id
</select>

@SpringBootTest
class ArticleInfoMapperTest {

    @Autowired
    private ArticleInfoMapper articleInfoMapper;

    @Test
    void selectByUserId() {
        System.out.println(articleInfoMapper.selectByUserId(1));
    }
}

由于这里的查询返回的结果是ArticleInfo对象,而这个类中并没有username、age、password属性,因此最终的结果并不会有,我们可以为这个类添加三个属性即可。由于实际开发中,多表查询的使用频率不是很高,因此这里不再演示了。

#{} 和 ${} 的区别

Mybatis 提供了两种参数赋值的方式,前面我们使用的是 #{},接下来我们学习 ${} 的方式,以及观察两者的差别。

java 复制代码
// ${}接收参数---Integer
List < UserInfo > selectAll4(Integer id);

<select id="selectAll4" resultType="com.springboot.mybatisdemo2.pojo.UserInfo">
    select * from user_info where id = ${id}
</select>

@Test
void selectAll4() {
    System.out.println(userInfoMapperXML.selectAll4(4));
}

虽然可以成功查询数据,但是${}并不是采用#{}那样的方式进行传递参数,而是直接把读取到的参数拼接在SQL语句上。

java 复制代码
// ${}接收参数-String
List < UserInfo > selectAll5(String username, String password);

<select id="selectAll5" resultType="com.springboot.mybatisdemo2.pojo.UserInfo">
    select * from user_info where username = ${username} and password = ${password}
</select>

@Test
void selectAll5() {
    System.out.println(userInfoMapperXML.selectAll5("admin", "admin_123456"));
}

由于这里在拼接的时候,是直接把参数的字面值拿出来拼接到SQL语句中,会导致原本的引号丢失,最终SQL语句解析错误。因此这里需要我们手动加上单引号。

同样传递对象时,如果是需要String类型的参数,也是需要加上单引号的。

从这里我们也可以看出如果我们传递String类型的参数时,编写出现SQL注入的语句,最终也会执行成功。

java 复制代码
// ${}接收参数-UserInfo对象
List < UserInfo > selectAll6(UserInfo userInfo);

<select id="selectAll6" resultType="com.springboot.mybatisdemo2.pojo.UserInfo">
    select * from user_info where username = '${username}' and password = '${password}'
</select>

@Test
void selectAll6() {
    UserInfo userInfo = new UserInfo();
    userInfo.setUsername("admin");
    // 可以将最后的单引号注释掉,也可以拼接成一个字符串
    userInfo.setPassword("' or 1 = '1");
    System.out.println(userInfoMapperXML.selectAll6(userInfo));
}

查询出所有用户的信息还是小事,就怕直接drop了。因此${}接收参数存在SQL注入的情况,本质就是因为其是直接拼接SQL语句,而不是和#{}一样采用占位符的方式占位。

{}是即时SQL,#{}是预编译SQL。SQL语句的执行流程是语法解析,优化SQL,替换占位符,执行SQL,如果是即时SQL的话,上述流程会每一步都执行,如果是预编译SQL的话,第一次执行时,上述步骤都会执行,但是当后续继续执行时,则只会执行替换占位符和执行SQL这两步,性能上有着不少的优化,其次就是SQL注入的问题,{}是直接拼接,而#{}会先对参数进行校验,如果存在 ' 这种特殊字符会对其进行转义处理,这样最终就不会出现SQL注入的问题了。

那是不是{}根本就用不到呢?其实不然,只要我们能够在service层正确处理SQL注入的情况,还是可以使用的,而且有些场景下只能使用{}。

例如,排序功能的实现,我们现在想要对查询的数据进行排序处理,用户传入的参数是

java 复制代码
// 排序查询
List<UserInfo> selectAll7(String sort);

<select id="selectAll7" resultType="com.springboot.mybatisdemo2.pojo.UserInfo">
    select * from user_info order by id #{sort}
</select>

@Test
void selectAll7() {
    System.out.println(userInfoMapperXML.selectAll7("desc"));
}

由于DESC是关键字,不能加单引号的,但是我们在传参的时候,是将其作为String类型进行传递的,因此Mybatis会自动为其加上单引号。所以这里只能使用 ${}了。虽然这里会出现SQL注入的风险,但是我们可以去判断用户传递参数是不是 ASC 或者 DESC,如果不是这两者中的一个的话,直接不处理,反之,则再去处理。或者可以学习某东和某宝的做法,直接将排序功能做成一个按钮,用户只能选择,并不能输入参数,这样也可以避免SQL注入的风险。

同样,模糊查询也只能使用 ${},而不能使用 #{},但同样这里我们不能限制传递的参数,但MySQL内置的函数concat可以用来连接字符串,这样就可以直接使用 #{} 来接收参数了。

数据库连接池

我们前面在学习JDBC时,每次增删改查操作都需要去手动创建连接,当SQL语句执行完毕之后,就需要去手动释放连接,整个过程是比较消耗资源的,特别是频繁创建与销毁连接时。前面学习多线程时,也是需要手动创建新线程,后来学习了如何使用线程池之后,就可以直接向线程池中拿线程,使用完之后,继续放到线程池中,这样的做法就是避免了频繁创建与销毁带来的时间开销。同样,数据库连接也可以存放到数据库连接池中,SpringBoot项目也是封装了数据库连接池:

这里使用到的数据库连接池是 Hikari,如果我们想要使用别的数据库连接池的话,也是可以在pom文件中导入依赖的。

XML 复制代码
<!-- springboot3.x版本 -->
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid-spring-boot-3-starter</artifactId>
   <version>1.2.21</version>
</dependency>

<!-- springboot2.x版本 -->
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid-spring-boot-starter</artifactId>
   <version>1.1.17</version>
</dependency>

再次启动测试用例,观察控制台的输出结果:

好啦!本期 初始JavaEE篇 ------ Mybatis操作数据库(上)的学习之旅 就到此结束啦!我们下一期再一起学习吧!

相关推荐
懒羊羊不懒@9 分钟前
Java基础语法—最小单位、及注释
java·c语言·开发语言·数据结构·学习·算法
ss27313 分钟前
手写Spring第4弹: Spring框架进化论:15年技术变迁:从XML配置到响应式编程的演进之路
xml·java·开发语言·后端·spring
DokiDoki之父24 分钟前
MyBatis—增删查改操作
java·spring boot·mybatis
李白你好30 分钟前
一款专业的多数据库安全评估工具,支持 **PostgreSQL、MySQL、Redis、MSSQL** 等多种数据库的后渗透操作
数据库·mysql·postgresql
兩尛41 分钟前
Spring面试
java·spring·面试
Java中文社群1 小时前
服务器被攻击!原因竟然是他?真没想到...
java·后端
恋红尘1 小时前
Mysql
数据库·mysql
Full Stack Developme1 小时前
java.nio 包详解
java·python·nio
paishishaba1 小时前
数据库设计原则
数据库
零千叶1 小时前
【面试】Java JVM 调优面试手册
java·开发语言·jvm