文章目录
- 一. MyBatis XML配置文件
- 1. 配置链接字符串和MyBatis
- 2. 写持久层代码
- 方法定义Interface
- 方法实现xml
- 测试
- 3. 增删改查
- 增:
- 删
- 改
- 查
- 二. 开发规范(mysql)
- 三. 其他查询操作
- 1. 多表查询
- 2. #{} 和 ${}(面试题)
- 使用
- 区别
- 排序功能
- like查询
- 三. 数据库连接池
- 四. 动态sql
- 1. < if > 标签
- 2. < trim >标签
- < where > 标签
- < set > 标签
- < foreach > 标签
- < sql > < include > 标签
一. MyBatis XML配置文件
MyBatis开发有两种方式:
- 注解
- XML
使⽤Mybatis的注解⽅式,主要是来完成⼀些简单的增删改查功能. 如果需要实现复杂的SQL功能,建议使⽤XML来配置映射语句,也就是将SQL语句写在XML配置⽂件中.
1. 配置链接字符串和MyBatis
添加配置:
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Drivermybatis:# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件mapper-locations: classpath:mapper/**.xml
在resources路径下, 创建mapper文件, 在mapper文件下创建**.xml文件, 以xml结尾的文件
和mapper-locations: classpath:后的路径对应即可
2. 写持久层代码
方法定义Interface
方法实现xml
MyBatis的固定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接口所对应的路径-->
<mapper namespace="com.bite.mybatis.mapper.UserInfoXmlMapper"></mapper>
查询:
<?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.bite.demo.mapper.UserInfoXMLMapper"><select id="queryAllUser" resultType="com.bite.demo.model.UserInfo">select * from userinfo</select>
</mapper>
- < mapper> 标签: 需要指定< namespace>属性, 表示命名空间, 值为mapper接口的全限定名, 即包名.类名
- < select>查询标签, 用来执行数据库的查询操作
- id : 是和接口中定义的方法名
- resultType : 是返回的数据类型
测试
3. 增删改查
增:
<insert id="insertUser">insert into userinfo (username, `password`, age, gender, phone) values(#{username}, #{password}, #{age}, #{gender}, #{phone})</insert>
返回自增id:
接口定义不变, 设置useGeneratedKeys 和keyProperty属性
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">insert into userinfo (username, `password`, age, gender, phone) values(#{username}, #{password}, #{age}, #{gender}, #{phone})</insert>
删
<delete id="deleteUser">delete from userinfo where id = #{id}</delete>
改
<update id="updateUser">update userinfo set username = #{username} where id = #{id}</update>
查
和注解一样, 映射也有三种解决办法:
1和3和注解一样
** xml结果映射:**
<resultMap id="BaseMap" type="com.bite.demo.model.UserInfo"><id column="id" property="id"></id><result column="delete_flag" property="deleteFlag"></result><result column="create_time" property="createTime"></result><result column="update_time" property="updateTime"></result></resultMap>
二. 开发规范(mysql)
阿里巴巴java开发手册的规范:
1.
2.
3.
三. 其他查询操作
1. 多表查询
- 准备工作
创建一个文章表
文章表的uid, 对应上述用户表的id
-- 创建⽂章表
DROP TABLE IF EXISTS articleinfo;
CREATE TABLE articleinfo (id INT PRIMARY KEY auto_increment,title VARCHAR ( 100 ) NOT NULL,content TEXT NOT NULL,uid INT NOT NULL,delete_flag TINYINT ( 4 ) DEFAULT 0 COMMENT '0正常, 1删除',create_time DATETIME DEFAULT now(),update_time DATETIME DEFAULT now() ) DEFAULT charset 'utf8mb4';-- 插⼊测试数据INSERT INTO articleinfo ( title, content, uid ) VALUES ( 'Java', 'Java正文', 1 );
sql: 查询id=1的作者的相关信息
selectta.id,ta.title,ta.content,ta.uid,tb.username,tb.age,tb.gender
fromarticleinfo ta
left join userinfo tb onta.uid = tb.id
whereta.id = 1
- 实体类:
@Data
public class ArticleInfo {private Integer id;private String title;private String content;private Integer uid;private Integer deleteFlag;private Date createTime;private Date updateTime;//用户相关信息private String username;private Integer age;private Integer gender;
}
- 接口定义:
@Mapper
public interface ArticleInfoMapper {@Select("SELECT ta.id,ta.title,ta.content,ta.uid,tb.username,tb.age,tb.gender " +"FROM articleinfo ta LEFT JOIN userinfo tb ON ta.uid = tb.id " +"WHERE ta.id = #{id}")ArticleInfo queryUserByUid(Integer id);}
- 测试类:
@SpringBootTest
class ArticleInfoMapperTest {@Autowiredprivate ArticleInfoMapper articleInfoMapper;@Testvoid queryUserByUid() {articleInfoMapper.queryUserByUid(1);}
}
2. #{} 和 ${}(面试题)
使用
- 传递Integer类型的参数
#{ }:
结果:
我们输⼊的参数并没有在后⾯拼接,id的值是使⽤ ? 进⾏占位. 这种SQL我们称之为**“预编译SQL”**
${ }:
结果:
这次的参数是直接拼接在SQL语句中, 叫做即时SQL
两种方法都不会报错 - 传递String类型的参数
#{ }
KaTeX parse error: Double superscript at position 213: …串作为参数时,需要添加引号' '̲, ⽤{} 不会拼接引号 ’ ‘, 导致程序报错
就需要我们手动添加’ ’
区别
1. #{} 和${} 的区别就是预编译SQL和即时SQL的区别
预编译SQL,编译⼀次之后会将编译后的SQL语句缓存起来,后⾯再次执⾏这条语句时,不会再次编译
(只是输⼊的参数不同),省去了解析优化等过程,以此来提⾼效率
2. $ { }存在sql注入问题(重点)
SQL注⼊:是通过操作输⼊的数据来修改事先定义好的SQL语句,以达到执⾏代码对服务器进⾏攻击的⽅法。
例如, 如果使用${}, 传递的参数为’ or 1=’ 1, 返回的数据用List接收, 就会发生
输入一个用户名, 就拿到了全部用户的数据, 这是非常不安全的
可以看出:
⽤于查询的字段,尽量使⽤ #{} 预查询的⽅式
排序功能
排序功能就是${} 的使用场景
mapper实现:
可以实现逆序返回的功能
如果使用#{}:
使用#{}, 将参数带入到sql中, 如果是字符串类型, 会自动加上’ ', 此时sql语句就变成:
select * from userinfo order by id ‘desc’, 语法错误
那么在完成排序功能时, 使用${ }, 也是存在sql注入的问题的, 所以一般需要排序的场景, 用户并不是自己输入的, 而是通过按钮等方式, 就行选择, 就避免了sql注入的问题
like查询
三. 数据库连接池
- Hikari : SpringBoot默认使⽤的数据库连接池
从Spring打印的日志就可以看出来
- Druid
如果我们想把默认的数据库连接池切换为Druid数据库连接池,只需要引⼊相关依赖即可
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId><version>1.2.21</version></dependency>
如果SpringBoot版本为2.X,使⽤druid-spring-boot-starter依赖
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.17</version></dependency>
四. 动态sql
1. < if > 标签
接口定义:
xml实现:
<insert id="insertUserByCondition">insert into userinfo (username, password, age, <if test="gender != null">gender,</if>phone)values (#{username},#{password},#{age},<if test="gender != null">#{gender},</if>#{phone})</insert>
注解实现(不推荐):
把上⾯SQL(包括标签),使⽤< script > < /script > 标签括起来就可以
@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>")Integer insertUserByCondition(UserInfo userInfo);
gender是有默认值的
上述没有设置gender, 所以会将gender设为默认值0, 而不是null
2. < trim >标签
<insert id="insertUserByCondition">insert into userinfo<trim prefix="(" suffix=")" suffixOverrides=","><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>values <trim prefix="(" suffix=")" suffixOverrides=","><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时, 那么phone后面就会多一个 ,
加上trim: 自动帮我们去掉 ,
< where > 标签
看下⾯这个场景, 系统会根据我们的筛选条件,动态组装where条件
< where > 只会在子元素有内容的情况下才插⼊where⼦句,⽽且会⾃动去除⼦句的开头的AND或OR
<select id="queryByCondition" resultType="com.bite.demo.model.UserInfo">select * from userinfo <where><if test="age != null">age = #{age}</if><if test="gender != null">and gender = #{gender}</if><if test="deleteFlag != null">and delete_flag = #{deleteFlag}</if></where>
</select>
< set > 标签
需求:根据传⼊的用户对象属性来更新用户数据,可以使⽤标签来指定动态内容.
<update id="updateUserByCondition">update userinfo<set><if test="age != null">age = #{age}</if><if test="username != null">username = #{username}</if><if test="gender != null">gender = #{gender}</if></set>where id = #{id}
</update>
以上标签也可以使⽤< trim prefix=“set” suffixOverrides=“,” > 替换
< foreach > 标签
需求:根据多个userid,删除用户数据
<delete id="deleteByIds">delete from userinfo where id in<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach> </delete>
< sql > < include > 标签
在xml映射⽂件中配置的SQL,有时可能会存在很多重复的⽚段,此时就会存在很多冗余的代码
<sql id="allColumn">id,username,age,gender,phone,delete_flag,create_time, update_time
</sql>
<select id="queryAllUser" resultType="com.bite.demo.model.UserInfo">select<include refid="allColumn"></include>from userinfo
</select>