🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
目录
- 1. 数据库连接池
- 1.1 为什么会有连接池
- 1.2 常用的数据库连接池
- 2. 动态SQL
- 2.1 ``<if>``标签
- 2.2 ``<trim>``标签
- 2.3 ``<where>``标签
- 2.4 ``<set>``标签
- 2.5 ``<for each>``标签
- 2.6 ``<include>``标签
- 3. 案例练习(表白墙)
- 3.1 配置文件
- 3.2 Mapper层代码
- 3.3 Service层代码
- 3.4 Controller层代码
1. 数据库连接池
1.1 为什么会有连接池
数据库连接池技术也是一种池化技术,他与线程池类似,在通过Spring连接数据库的时候,避免了频繁的创建和销毁与数据库的连接.保证了资源的合理利用.
没有使用数据库连接池的情况: 在每一次在Spring中执行SQL语句的时候,都会先创建一个与数据库的连接对象,在执行完SQL语句之后,再关闭SQL语句,这种重复创建和销毁对象的行为比较浪费系统资源.
使用数据连接池的情况: 在程序启动的时候,会在连接池中创建Collection对象,在执行SQL语句的时候,会在连接池中申请一个连接对象,在执行SQL语句之后,又会把线程归还给连接池.
1.2 常用的数据库连接池
• C3P0
• DBCP
• Druid
• Hikari
目前比较流行的是Hikari,Druid,其中,Druid是阿里巴巴开源项目中的连接池.
其中Hikari是一个Spring程序中默认使用的连接池.如果想把连接池切换为Druid,我们需要在pom文件中引入依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.21</version>
</dependency>
2. 动态SQL
动态SQL可以完成不同场景下的SQL拼接.
2.1 <if>
标签
在我们注册用户的时候,我们有一个这样的问题,有时候有的选项不是必填项.在添加用户的时候SQL字段个数是不确定的.这时候就需要我们使用<if>
标签了.比如gender性别是非必填字段:
接口定义:
public Integer insertUser2(UserInfo userInfo);
sql:
<insert id="insertUser2">
insert into userinfo (
id,
username,
password,
age,
<if test="gender != null">
gender,
</if>
phone
) values (
#{id},
#{username},
#{password},
#{age},
<if test="gender != null">
#{gender},
</if>
#{phone}
)
</insert>
或者我们也可以使用注解的方式,使用<script></script>
标签把上面的xml语句括起来即可.但是我们不推荐用这种做法.
@Insert("<script>" +
"INSERT INTO userinfo (username,`password`,age," +
"<if test='gender!=null'>gender,</if>" +
"phone)" +
"VALUES(#{username},#{age}," +
"<if test='gender!=null'>#{gender},</if>" +
"#{phone})"+
"</script>")
public Integer insertUser2(UserInfo userInfo);
注意if中的gender是对象的属性,不是SQL的字段,因为对象是从前端传过来的,我们在判断的时候,是判断前端有没有传值过来,而前段的值就是传到后端的方法参数中的.
2.2 <trim>
标签
上面只使用if标签有一定的问题.要是我们在拼接SQL语句的时候,if标签在最后一个字段,比如:
<insert id="insertUser2">
insert into userinfo (
id,
username,
password,
age,
gender,
<if test="phone != null">
phone
</if>
) values (
#{id},
#{username},
#{password},
#{age},
#{gender},
<if test="phone != null">
#{phone}
</if>
)
</insert>
当我们没有phone属性的时候,我们在gender字段后面就会多上一个逗号,这显然不符合sql的语法,所以我们就需要使用<trim>
标签.
标签中有如下属性:
• prefix:表示整个语句块,以prefix的值作为前缀
• suffix:表示整个语句块,以suffix的值作为后缀
• prefixOverrides:表示整个语句块要去除掉的前缀
• suffixOverrides:表示整个语句块要去除掉的后缀
调整上面的插入语句:
<insert id="insertUser3">
insert into userinfo
<trim prefix="(" suffix=")" suffixOverrides="," prefixOverrides=",">
id,
username,
password,
age,
gender,
<if test="phone != null">
phone
</if>
</trim>
values
<trim prefix="(" prefixOverrides="," suffix=")" suffixOverrides=",">
#{id},
#{username},
#{password},
#{age},
#{gender},
<if test="phone != null">
#{phone}
</if>
</trim>
</insert>
假如所有的字段都是可选字段:
<insert id="insertUser4">
insert into userinfo
<trim prefixOverrides="," suffixOverrides="," suffix=")" prefix="(">
<if test="id != null">
id,
</if>
<if test="username != null">
username,
</if>
<if test="password != null">
password,
</if>
<if test="age != null">
age,
</if>
<if test="phone != null">
phone
</if>
</trim>
values
<trim prefix="(" suffix=")" suffixOverrides="," prefixOverrides=",">
<if test="id != null">
#{id},
</if>
<if test="username != null">
#{username},
</if>
<if test="password != null">
#{password},
</if>
<if test="age != null">
#{age},
</if>
<if test="gender != null">
#{gender},
</if>
<if test="phone != null">
#{phone}
</if>
</trim>
</insert>
trim标签中的参数的用意就是:在前面和后面只要有逗号,就都会去掉,之后再在sql语句中的前后拼接上括号.
这个标签就是把<trim>
中的内容当做一个字符串,对这个字符串进行整体加减前后缀.
在注解中写的方法和上面的if标签是一样的,这里不再赘述.
2.3 <where>
标签
下面这个场景,系统会根据我们的筛选条件,动态组装where条件.
这样的场景该如何实现呢?下面我们来看例子.
传入的用户对象,根据属性做where条件查询,用户对象中属性不为null的,都为查询条件.
接口定义:
public List<UserInfo> selectUser1(UserInfo userInfo);
根据传过来的对象限制查询条件.
sql:
<select id="selectUser1" resultType="com.jrj.mybatis.UserInfo">
select * from userinfo
<where>
<if test="gender != null">
#{gender},
</if>
<if test="age != null">
#{age},
</if>
<if test="deleteFlag != null">
#{deleteFlag}
</if>
</where>
</select>
<where>
标签和<trim>
标签类似,where可以去除掉前后的and和or,如果where后面没有字段的话,就没有where语句了,where关键字不予保留.效果和<trim prefix="where" prefixOverrides="and">
相同,但是使用这个标签的时候,当没有限制条件的时候,where关键字就会保留下来.
2.4 <set>
标签
根据传入的用户对象属性来更新用户数据,可以使用标签来指定动态内容.
方法接口:
public Integer updateUser1(UserInfo userInfo);
sql:
<update id="updateUser1">
update userinfo
<set>
<if test="username != null">
username = #{username},
</if>
<if test="age != null">
age = #{age},
</if>
<if test="gender != null">
gender = #{gender}
</if>
</set> where id = #{id}
</update>
<set>
标签和上面的<where>
标签一样,会自动去除逗号,也会根据是否有更新字段来判断是否要添加set关键字.与<trim prefix="set" suffixOverrides=",">
效果一样,但是在没有传入跟新字段的时候,不会去掉set关键字.
2.5 <for each>
标签
对集合进行遍历的时候,可以用这个标签,一般与sql语句中的in配合使用.
对集合进行遍历时可以使用该标签。标签有如下属性:
• collection:绑定方法参数中的集合,如List,Set,Map或数组对象
• item:遍历时的每⼀个对象
• open:语句块开头的字符串
• close:语句块结束的字符串
• separator:每次遍历之间间隔的字符串
比如根据多个用户id删除用户数据.
接口:
public Integer updateDeleteFlag1(List<UserInfo> userList);
sql:
<update id="updateDeleteFlag1">
update userinfo set delet_flag
where id in
<foreach collection="userList" item="id" open="(" close=")">
#{id}
</foreach>
</update>
这里我们在删除用户数据的时候,使用的是逻辑删除的方式:
删除方式一共有两种,一种是逻辑删除,一种是物理删除,物理删除就是使用Delete语句,在计算机的存储空间中彻底删除,想要回复只能通过日志回滚的方式进行恢复,非常麻烦.而逻辑删除就是把表中每个数据的必备字段,delete_flag标记为无效的数值,并没有从硬盘上真正删除掉,恢复的时候只需要把这个数值改成有效数值即可.我们在企业开发的时候,一般用的都是逻辑删除.
[补充] 其中的collection参数也可以用list1,list2来表示,和前面的方法形参与sql语句传参类似.
2.6 <include>
标签
这个标签通常与<sql>
标签配合使用,在xml文件中,有一些sql语句是赘余的,即sql语句中的赘余片段.
我们可以对重复的代码片段段进行抽取,将其通过 <sql>
标签封装到⼀个SQL片段.之后在每一个sql语句中使用<include>
标签进行引用即可.
<sql>
: 对可以重复引用的sql语句进行定义,在参数id中定义该sql片段的名字.<include>
: 通过属性refid,指定引用的sql片段.
<sql id="selectAllColumn">
id,username,password,age,gender,phone,delete_flag,create_time,update_time
</sql>
<select id="selectAllUser2" resultType="com.jrj.mybatis.UserInfo">
select
<include refid="selectAllColumn"></include>
from userinfo
</select>
3. 案例练习(表白墙)
前面我们写了表白墙,但是在服务器重启之后,就会清空之前的数据,数据无法永久保留,这时候就需要引入MyBatis了,我们需要把数据存储在数据库中.
3.1 配置文件
spring:
application:
name: vindicatewall
# 数据库连接配置
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
username: root
password: qwe123524
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
configuration: # 配置打印 MyBatis⽇志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true #配置驼峰⾃动转换
需要配置的选项有这几个,第一个是数据库相关配置,包括数据库url,用户名,密码,MySQl驱动类.其次,需要配置MyBatis中的日志打印和驼峰自动转换.
3.2 Mapper层代码
@Mapper
public interface MessageMapper {
@Insert("insert into message_info (`from`,`to`,`message`) values " +
"(#{from},#{to},#{message})")
public Integer updateMessage(Message message);
@Select("select * from message_info")
public List<Message> selectAllMessage();
}
3.3 Service层代码
@Service
public class MessageService {
@Autowired
public MessageMapper messageMapper;
public Integer updateMessage(Message message){
return messageMapper.updateMessage(message);
}
public List<Message> selectAllMessage(){
return messageMapper.selectAllMessage();
}
}
3.4 Controller层代码
@RestController
@RequestMapping("/messagewall")
public class MessageController {
@Autowired
public MessageService messageService;
@RequestMapping("/publish")
public Boolean updateMessage(Message message){
if (StringUtils.hasLength(message.getFrom())&&
StringUtils.hasLength(message.getTo())&&
StringUtils.hasLength(message.getMessage())){
messageService.updateMessage(message);
return true;
}
return false;
}
@RequestMapping("/getlist")
public List<Message> selectAllMessage(){
return messageService.selectAllMessage();
}
}
Postman测试后端代码:
数据库已更新: