目录
2. 引入Mybatis的相关依赖,配置Mybatis(数据库连接信息)
在application.properties中引入数据库连接配置
XML配置文件规范 (写在资源文件(resources)中用'/'当做'.'建立多级包)
入门
是什么?
持久层框架,用于简化JDBC的开发。
持久层:就是数据访问层(dao),是用来操作数据库的。
框架:一个半成品软件,是一套可重用的、通用的、软件基础代码模型。
使用Mybatis操作数据库
在Mybatis中编写SQL查询代码,发送给数据库执行,数据库执行后返回结果。
Mybatis会把数据库执行的查询结果,使用实体类封装起来(一行记录对应一个实体类对象)
操作数据库的步骤
1. 准备工作
创建springboot工程,并导入 mybatis的起步依赖、mysql的驱动包。
<dependencies>
<!-- mybatis起步依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency><!-- mysql驱动包依赖 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
数据库表user
实体类User
2. 引入Mybatis的相关依赖,配置Mybatis(数据库连接信息)
1.连接数据库的四大参数:
MySQL驱动类
登录名
密码
数据库连接字符串
2.在springboot项目中,可以编写application.properties文件,配置数据库连接信息。我们要连接数据库,就需要配置数据库连接的基本信息,包括:driver-class-name、url 、username,password。
application.properties:
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=1234
3. 编写SQL语句(注解/XML)
在创建出来的springboot工程中,在引导(启动)类所在包下,在创建一个包 mapper。在mapper包下创建一个接口 UserMapper ,这是一个持久层接口(Mybatis的持久层接口规范一般都叫 XxxMapper)。
UserMapper:
@Mapper
public interface UserMapper {
//查询所有用户数据
@Select("select * from user")
public List<User> list();
}
@Mapper注解:
表示是mybatis中的Mapper接口
程序运行时:框架会自动生成接口的实现类对象(动态代理对象),并给交Spring的IOC容器管理
@Select注解:
就是select查询,用于书写select查询语句
4 单元测试
@SpringBootTest
public class MybatisQuickstartApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testList(){
List<User> userList = userMapper.list();
for (User user : userList) {
System.out.println(user);
}
}}
解决SQL警告与提示
默认我们在UserMapper接口上的@Select注解中编写SQL语句是没有提示的。如果想让idea给出提示,可以做如下配置:
选中语句,右击show context Actions ->inject language or reference ->mysql
配置完成之后,发现SQL语句中的关键字有提示了,但还存在不识别表名(列名)的情况:
产生原因:Idea和数据库没有建立连接,不识别表信息
解决方案:在Idea中配置MySQL数据库连接
JDBC(了解)
sun公司定义的一套操作所有关系型数据库的规范,即api接口。
各个数据库厂商去实现这套接口,提供数据库驱动jar包。
真正执行的代码是驱动jar包中的实现类。
Mybatis框架,就是对原始的JDBC程序的封装。
数据库连接池
是个容器,负责分配、管理数据库连接(Connection),程序在启动时,数据库连接池中创建一定数量的Connection对象
允许应用程序重复使用一个现有的数据库连接,而不重新建立
释放空闲时间超时的连接,来避免因为没有释放连接而引起的数据库连接遗漏
好处
1. 资源重用
2. 提升系统响应速度
3. 避免数据库连接遗漏
怎么样实现数据库连接池
官方(sun)提供了数据库连接池标准(javax.sql.DataSource接口)
功能:获取连接 public Connection getConnection() throws SQLException;
第三方组织必须按照DataSource接口实现
常见的数据库连接池
C3P0
DBCP
Druid(德鲁伊)性能优越,阿里巴巴开源的数据库连接池项目 ,功能强大,性能优秀,是Java语言最好的数据库连接池之一
Hikari (springboot默认)(追光者)性能优越
默认的数据库连接池切换为Druid数据库连接池
参考官方地址:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
在pom.xml文件中引入依赖
<dependency>
<!-- Druid连接池依赖 -->
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
在application.properties中引入数据库连接配置
方式1:
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/mybatis
spring.datasource.druid.username=root
spring.datasource.druid.password=1234
方式2:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
spring.datasource.username=root
spring.datasource.password=1234
lombok
通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提高效率。
注解
@Getter/@Setter为所有的属性提供get/set方法
@ToString会给类自动生成易阅读的 toString 方法
@EqualsAndHashCode根据类所拥有的非静态字段自动重写 equals 方法和 hashCode 方法
@Data提供了更综合的生成代码功能(@Getter + @Setter + @ToString + @EqualsAndHashCode)
@NoArgsConstructor为实体类生成无参的构造器方法
@AllArgsConstructor为实体类生成除了static修饰的字段之外带有各参数的构造器方法。
使用
第1步:在pom.xml文件中引入依赖
<!-- 在springboot的父工程中,已经集成了lombok并指定了版本号,故当前引入依赖时不需要指定version -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
第2步:在实体类上添加注解
在实体类上添加了@Data注解,那么这个类在编译时期,就会生成getter/setter、equals、hashcode、toString等方法。
说明:@Data注解中不包含全参构造方法,通常在实体类上,还会添加上:全参构造、无参构造
注意事项
Lombok会在编译时,会自动生成对应的java代码
在使用lombok时,还需要安装一个lombok的插件(新版本的IDEA中自带)
基础操作
预编译SQL
SQL注入
通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。输入 ' or '1'='1
优势
1. 性能更高
编译一次之后会将编译后的SQL语句缓存起来,后面再次执行这条语句时,不会再次编译。(只是输入的参数不同)
2. 更安全(防止SQL注入)
将敏感字进行转义,保障SQL的安全性
参数占位符
#{...}
把参数当做整体传入预编译SQL,会自动设置参数值,能够防止sql注入
使用时机:参数传递,都使用#{…},
解决SQL注入的原因:当做字符串带引号作为参数会进行转义,
${...}
拼接SQL。直接将数据拼接在SQL语句中,存在SQL注入问题
使用时机:如果对表名、列表进行动态设置时使用
注意事项:在项目开发中,建议使用#{...},生成预编译SQL,防止SQL注入安全。
1. 查询
根据主键ID查询
接口方法
@Mapper
public interface EmpMapper {
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id=#{id}")
public Emp getById(Integer id);
}@SpringBootTest
class SpringbootMybatisCrudApplicationTests {
@Autowired
private EmpMapper empMapper;@Test
public void testGetById(){
Emp emp = empMapper.getById(1);
System.out.println(emp);
}
}
数据封装
返回的结果中大部分字段是有值的,但是仍个字段是没有值的,而数据库中是有对应的字段值的,这是为什么呢?
原因
实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装。
如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装。
解决方案
1. 起别名
在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样
2. 结果映射
通过 @Results及@Result 进行手动结果映射
@Results({
@Result(column = "数据库的字段名",property = "对应的属性名"),
@Result(column = "emp_id",property = "empId"),
...
})
3. 开启驼峰命名
如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射
mybatis.configuration.map-underscore-to-camel-case=true
驼峰命名规则:
abc_xyz => abcXyz
表中字段名:abc_xyz
类中属性名:abcXyz
要使用驼峰命名前提是 实体类的属性 与 数据库表中的字段名严格遵守驼峰命名。
条件查询
接口方法
方式一
@Mapper
public interface EmpMapper {
@Select("select * from emp " +
"where name like '%${name}%' " +
"and gender = #{gender} " +
"and entrydate between #{begin} and #{end} " +
"order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}
注意事项:
1. 方法中的形参名和SQL语句中的参数占位符名保持一致
2. 模糊查询使用${...}进行字符串拼接,这种方式呢,由于是字符串拼接,并不是预编译的形式,所以效率不高、且存在sql注入风险。
方式二(解决SQL注入风险)
@Mapper
public interface EmpMapper {@Select("select * from emp " +
"where name like concat('%',#{name},'%') " +
"and gender = #{gender} " +
"and entrydate between #{begin} and #{end} " +
"order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);}
使用MySQL提供的字符串拼接函数:concat('%' , '关键字' , '%')
执行结果:生成的SQL都是预编译的SQL语句(性能高、安全)
参数名说明
我们需要保证接口中方法的形参名和SQL语句中的参数占位符名相同。
参数名在不同的SpringBoot版本中,处理方案还不同:
springBoot的2.x版本(保证参数名一致)
SpringBoot的父工程对compiler编译插件进行了默认的参数parameters配置,使得在编译时,会在生成的字节码文件中保留原方法形参的名称,所以#{…}里面可以直接通过形参名获取对应的值
springBoot的1.x版本/单独使用mybatis(使用@Param注解来指定SQL语句中的参数名)
在编译时,生成的字节码文件当中,不会保留Mapper接口中方法的形参名称,而是使用var1、var2、...这样的形参名字,此时要获取参数值时,就要通过@Param注解来指定SQL语句中的参数名
2. 新增
接口方法
@Mapper
public interface EmpMapper {@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
public void insert(Emp emp);}
测试类
@SpringBootTest
class SpringbootMybatisCrudApplicationTests {
@Autowired
private EmpMapper empMapper;@Test
public void testInsert(){
//创建员工对象
Emp emp = new Emp();
emp.setUsername("tom");
emp.setName("汤姆");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setJob((short)1);
emp.setEntrydate(LocalDate.of(2000,1,1));
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(1);
//调用添加方法
empMapper.insert(emp);
}
}
#{...} 里面写的名称是对象的属性名
主键返回
数据添加成功后,需要获取插入数据库数据的主键
在Mapper接口中的方法上添加一个Options注解,并在注解中指定属性useGeneratedKeys=true和keyProperty="实体类属性名"
主键返回代码实现
@Mapper
public interface EmpMapper {
//会自动将生成的主键值,赋值给emp对象的id属性
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
public void insert(Emp emp);}
@SpringBootTest
class SpringbootMybatisCrudApplicationTests {
@Autowired
private EmpMapper empMapper;@Test
public void testInsert(){
//创建员工对象
Emp emp = new Emp();
emp.setUsername("jack");
emp.setName("杰克");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setJob((short)1);
emp.setEntrydate(LocalDate.of(2000,1,1));
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(1);
//调用添加方法
empMapper.insert(emp);System.out.println(emp.getDeptId());
}
}
3. 更新
接口方法
@Mapper
public interface EmpMapper {
/**
* 根据id修改员工信息
* @param emp
*/
@Update("update emp set username=#{username}, name=#{name}, gender=#{gender}, image=#{image}, job=#{job}, entrydate=#{entrydate}, dept_id=#{deptId}, update_time=#{updateTime} where id=#{id}")
public void update(Emp emp);
}
@SpringBootTest
class SpringbootMybatisCrudApplicationTests {
@Autowired
private EmpMapper empMapper;@Test
public void testUpdate(){
//要修改的员工信息
Emp emp = new Emp();
emp.setId(23);
emp.setUsername("songdaxia");
emp.setPassword(null);
emp.setName("老宋");
emp.setImage("2.jpg");
emp.setGender((short)1);
emp.setJob((short)2);
emp.setEntrydate(LocalDate.of(2012,1,1));
emp.setCreateTime(null);
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptId(2);
//调用方法,修改员工数据
empMapper.update(emp);
}
}
4. 删除
根据主键ID删除
根据主键ID批量删除
接口方法
@Mapper
public interface EmpMapper {
/**
* 根据id删除数据
* @param id 用户id
*/
@Delete("delete from emp where id = #{id}")//使用#{key}方式获取方法中的参数值
public void delete(Integer id);
}
@Delete注解:用于编写delete操作的SQL语句
如果mapper接口方法形参只有一个普通类型的参数,#{…} 里面的属性名可以随便写,如:#{id}、#{value}。但是建议保持名字一致。
日志输入
1. 打开application.properties文件
2. 开启mybatis的日志,并指定输出到控制台
#指定mybatis输出日志的位置, 输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
Mybatis的XML配置文件
Mybatis的开发有两种方式
1. 注解(代码简单时使用)
@Select
@Delete
@Update
@Insert
2. XML(复杂时使用)
XML配置文件规范 (写在资源文件(resources)中用'/'当做'.'建立多级包)
如果需要实现复杂的SQL功能,建议使用XML来配置映射语句,也就是将SQL语句写在XML配置文件中。
规范(mapper.java和mapper.xml文件是怎样关联的)
1. XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)
2. XML映射文件的namespace属性为Mapper接口全限定名一致
3. XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致。
<select>标签:就是用于编写select查询语句的。
resultType属性,指的是查询返回的单条记录所封装的类型。
XML配置文件实现
创建XML映射文件
编写XML映射文件
xml映射文件中的dtd约束,直接从mybatis官网复制即可
https://mybatis.net.cn/
<?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="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
namespace="org.mybatis.example.BlogMapper"
(表示与哪个Mapper接口文件关联,所以这里写的是Mapper接口路径)
<select id="接口中的方法名" resultType="方法的返回值类的路径"></select>
可以写<update id="接口中的方法名"></update>标签,仅有id,没有返回值类型
两个文件
接口文件
EmpMapper.java 实现的是接口中的方法
xml文件
EmpMapper.xml 定义的 sql语句
当我们调用接口中的方法,就会执行XML文件中的sql语句(根据id找到sql语句)
MybatisX插件的使用
基于IDEA的快速开发Mybatis的插件,为效率而生
当时用aliyun创建的项目要是的方法用@Param("属性") 类型 属性
动态SQL
SQL语句会随着用户的输入或外部条件的变化而变化
一定要注意SQL结尾的分号,容易报错
动态SQL-if
<if>
用于判断条件是否成立。用test属性进行条件判断,如果条件为true,则拼接SQL。
<if test="条件表达式">
要拼接的sql语句
</if>
条件表达式 (一般是属性)
要拼接的sql语句(一般用得字段和属性)
<where>
条件查询
动态拼接where
会自动去除子句的开头的AND或OR
<set>
更新数据
动态拼接set
会删掉额外的逗号(用于update语句中)
动态SQL-foreach
遍历deleteByIds方法中传递的参数ids集合
<foreach collection="集合名称"
item="集合遍历出来的元素/项"
separator="每一次遍历使用的分隔符"
open="遍历开始前拼接的片段"
close="遍历结束后拼接的片段">
#{id}//这里的id与item元素名称一致
</foreach>
动态SQL-sql&include
通过<sql>标签封装到一个SQL片段,然后再通过<include>标签进行引用。
<sql>:可重用的SQL片段
<sql id="名称">
select *
from emp
</sql>
<sql id="commonSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp
</sql>
<include>:通过属性refid,引入SQL片段
<include refid="sql的id名称"></include>或者<include refid="sql的id名称"/>
<select id="list" resultType="com.itheima.pojo.Emp">
<include refid="commonSelect"/></include>
<where>
<if test="name != null">
name like concat('%',#{name},'%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>