MyBatis 是一款优秀的持久层框架,用于简化JDBC的开发。
说人话就是连接数据库并执行SQL的框架。
文章目录
- 0 JDBC简介及流程
- 0.1 DriverManager / Connection
- 0.2 ResultSet
- 0.3 PreparedStatement
- 1 SQL注入
- 2 流程
- 1 MyBatis通过注解执行SQL语句
- 1.1 MyBatis入门:select
- Lombok
- 1.2 依葫芦画瓢:删除
- 1.3 插入
- 1.4 更新
- 2 通过XML映射文件配置SQL语句
- 小插件
- 3 动态SQL
- if
- foreach
- sql
- 4 文件设置总结
0 JDBC简介及流程
【这一节完全可以跳过,理解它是一个连接数据库 & 执行sql的jar包就好,因为后面基本在用MyBatis,基本上不咋直接使JDBC】
Java DataBase Connectivity,JDBC就是使用Java语言操作关系型数据库的一套API:
- 官方定义的一套操作所有关系型数据库的规则,即接口
- 各个数据库厂商实现这套接口,提供数据库驱动jar包
- 我们可以使用这套JDBC接口编程,真正执行的代码是驱动jar包的实现类。
使用的步骤:首先导入驱动jar包。
我的MySQL驱动jar包:F:\MySQL\Program Files (x86)\MySQL\Connector J 8.0\mysql-connector-j-8.0.32.jar
将驱动jar包放入项目下的lib文件夹,并设置add as library。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
// 1 注册驱动
// sql 5之后可以不写这一条
Class.ForName("com.mysql.cj.jdbc.Driver");
// 2 连接数据库
url = "jdbc:mysql://127.0.0.1:3306/askcourse";
Connection conn = DriverManager.getConnection(url, username, password);
// 3 定义SQL语句
sql = "";
// 4 获取执行SQL的对象
Statement stmt = conn.createStatement();
// 5 执行SQL
stmt.executeUpdate(sql);
// 6 处理返回结果
// 7 释放资源
stmt.close();
conn.close();
0.1 DriverManager / Connection
1、注册驱动
Class.ForName("com.mysql.cj.jdbc.Driver");
Driver类源码中,这句话对应着:
DriverManager.registerDriver(new Driver())
2、从DriverManger类得到数据库连接。
Connection conn = DriverManger.getConnection('jdbc:mysql://127.0.0.1:3306/数据库名', 用户名, 密码)
0.2 ResultSet
结果集对象,封装了查询语句的结果。
ResultSet res = stmt.executeQuery(sql);
获取查询结果:
boolean next(): 将光标从当前位置移动一行,判断该行是否为有效行
xxx getXxx(): 获取数据
0.3 PreparedStatement
1 SQL注入
SQL注入例子:无论何时,这样拼起来都是true
String name ="hfkjsfhskj";
String pwd = " or '1' ='1"
String sql = "select * from tb_user where username = " + name + " and password = " + pwd;
System.out.printIn(sql);
select * from tb_user where username = 'hfkjsfhskj' and password = '' or '1' = '1'
2 流程
1、获取Connection。
String url = "jdbc:mysql://127.0.0.1:3306/askcourse?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT";
String user = "root";
String password = "********";
Connection conn = DriverManager.getConnection(url, user, password);
2、预编译SQL并填入参数。
String DNO = "C10";
String sql = "SELECT * FROM employee WHERE DNO = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, DNO);
3、执行SQL语句。
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("DNO"));
}
4、关掉所有的东西。
rs.close();
pstmt.close();
conn.close();
1 MyBatis通过注解执行SQL语句
1.1 MyBatis入门:select
加入Maven依赖,配置连接信息,创建相应实体,创建Mapper
及查询方法,添加相应注解。
1、小tips:连接数据库
2、在pom.xml中加入maven依赖,前者为mybatis的bootstarter,后者为mysql的驱动连接包。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
3、在Springboot项目中的application.properties
中配置Mybatis数据库连接信息。
3、创建一个实体类User,用于和数据库中的表属性相关联
4、创建UserMapper,一开始的报错Missing method body, or declare abstract
是因为,这实际上是个Interface
,误写为了Class
,改一下就好。
5、在test文件夹中的HelloworldApplicationTests
应用中,实例化一个UserMapper
,并新建testListUser
测试。
@SpringBootTest
class HelloworldApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void testListUser() {
List<User> userList = userMapper.list();
userList.stream().forEach(System.out::println);
}
}
Lombok
maven依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
1.2 依葫芦画瓢:删除
1、新建一个FinishProblemMapper,用于对finishProblem表进行操作。@Mapper
注解和@Delete
注解。使用#{param}
在SQL语句中写入参数。根据主键删除元素。
package com.example.helloworld.mapper;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface FinishProblemMapper {
/**
* 根据wid与problemId删除指定的做题记录
* @param wid
* @param problemId
*/
@Delete("delete from finished where wid = #{wid} and problemId = #{problemId}")
public void deleteById(Integer wid, Integer problemId);
}
2、在配置文件中设置mybatis日志
# the log of mybatis
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
3、在test中新建Test
@SpringBootTest
class HelloworldApplicationTests {
@Autowired
private FinishProblemMapper finishProblemMapper;
@Test
void testDeleteFinishProblem() {
finishProblemMapper.deleteById(72, 21);
}
}
1.3 插入
传入的参数可以是一个实体。
@Options
注解会自动将生成的主键值,赋值给problem的problemId属性。(自动生成主键值
@Mapper
public interface ProblemMapper {
/**
* 向Problem表中插入一行problem数据
* @param problem
*/
@Insert("insert into problem(problemId, name, url, day) VALUE (#{problemId}, #{name}, #{url}, #{day})")
public void insert(Problem problem);
}
测试:
void testProblemInsert() {
problemMapper.insert(new Problem(202, "快乐数", "https://leetcode.cn/problems/happy-number/", 6));
}
可以设置主键自增,但要先在数据库中进行相应设置。
@Options(keyProperty = "wid", useGeneratedKeys = true)
1.4 更新
类似地,传入的参数可以是一个实体。
2 通过XML映射文件配置SQL语句
核心:通过xml文件的配置,确定项目中某个Mapper的某个方法对应的SQL语句。
动机:使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java注解不仅力不从心,还会让本就复杂的SQL语句显得更加混乱不堪。选择何种方式来配置映射,以及是否要统一映射语句的形式,完全取决于你和你的团队。
当调用ProblemMapper
中的selectByDay
方法时,Mybatis框架首先会找到相应的xml配置文件,然后找到xml配置文件中的对应方法,并执行对应的SQL语句。
<?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.helloworld.mapper.ProblemMapper">
<select id="selectByDay" resultType="com.example.helloworld.model.Problem">
select * from problem where day = #{day} order by problemId
</select>
</mapper>
执行test:
小插件
MyBatisX
:安装后点击Mapper
中的方法就可以自动定位到xml文件中的SQL语句位置。
3 动态SQL
if
随着用户的输入或者外部条件的变化而变化的SQL语句。
情景1:希望查询参数为空时select *
,不为空时按条件查询,使用<where>
和<if>
。
情景2:更新时仅更新部分属性,使用<set>
和<if>
。
<where>
可以自动地生成WHERE
语句,当语句中没有内容时不会显示,并且可以自动地去掉多余的and或者or。
<set>
可以自动地生成set
语句,当语句中没有内容时不会显示,并且可以自动地去掉多余的逗号。
foreach
<!-- 批量删除做题记录 -->
<delete id="deleteByIds">
delete from finished where wid in
<!--集合名,元素名,分隔符,开始拼接符号,结束拼接符号-->
<foreach collection="idList" item="wid" separator="," open="(" close=")">
#{wid}
</foreach>
</delete>
sql
实现重复sql代码的复用。
如下,通过<sql>
和<include>
,实现了commonSelect
的复用。
<?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.helloworld.mapper.ProblemMapper">
<sql id="commonSelect">
select problemId, name, url, day from problem
</sql>
<select id="selectByDay" resultType="com.example.helloworld.model.Problem">
<include refid="commonSelect"/>
where day = #{day} order by problemId
</select>
<select id="list" resultType="com.example.helloworld.model.Problem">
<include refid="commonSelect"/>
<where>
<if test="problemId != null"> problemId = #{problemId}</if>
<if test="name != null"> and name = #{name}</if>
<if test="day != null"> and day = #{day} </if>
</where>
</select>
</mapper>
4 文件设置总结
application.properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/problem_tiktok
spring.datasource.username=root
spring.datasource.password=********
# the log of mybatis
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
pom.xml
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>