Mybatis
什么是Mybatis
- 是一款优秀的持久层框架.
- 支持定制化
SQL
,存储过程以及高级映射. - 避免了几乎所有
JDBC
代码和手动设置参数以及获取结果集. - 可以使用简单的XML或注解来配置和映射原生类型接口和
java
的POJO
(Plain Old Java Objects,普通老式Java对象)为数据库中记录.
什么是ORM
ORM
,(Object-Relationl Mapping
)对象关系映射,它的作用是在关系型数据库和对象之间做一个映射处理
什么是持久化
- 数据持久化
- 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
- 内存:断电即失
- 数据库持久化,
io
文件持久化
什么是持久层
- 完成持久化工作的代码块
- 相对于瞬时来说,持久层可以理解为数据保存在数据库或硬盘一类可以长时间的保存于设备中,不像放在内存中那样断电就会消失的,也就是把数据存放在持久层设备上
为什么需要Mybatis
?
- 帮助程序员将数据存入到数据库中
- 方便
- 传统的
JDBC
代码太复杂,简化,框架,自动化 - 优点
- 简单易学
- 灵活
SQL
和代码分离,提高了可维护性- 提供映射标签,支持对象与数据库的
orm
字段关系映射 - 提供对象关系映射标签,支持对象关系组建维护
- 提供
xml
标签,支持编写动态SQL
JDBC
的缺点:
- 需要手动的完成面向对象的Java语言,面向关系的数据库之间数据的转换,代码繁琐无技术含量,影响了开发效率,
mybatis
与Hibernate的比较
Mybatis
是一个半自动ORM
框架,其本质是对JDBC
的封装.使用Mybatis
重点需要程序员编写SQL
命令,不需要写一行JDBC
代码Hibernate
是一个全自动ORM
框架,因为Hibernate
创建了Java对象和数据库表之间的完整映射,可以完全以面向对象的思想来操作数据库,程序员不需要手写SQL
语句- Hibernate缺点:因为Hibernate自己可以生成
SQL
语句,不需要程序员编写,但生成的SQL
语句较为复杂,不便于优化.
- Hibernate缺点:因为Hibernate自己可以生成
Mybatis
程序步骤:
-
搭建环境
- 搭建数据库
- 新建一个普通的maven项目
-
导入jar包
<!-- mybatis依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!-- mysql依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <!-- Junit依赖 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
-
编写代码
- 编写
mybatis
的核心配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--configuration核心配置文件--> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="825520"/> </dataSource> </environment> </environments> </configuration>
- 编写工具类
/** * 工具类 */ public class MyUtils { private static SqlSessionFactory sqlSessionFactory; //添加静态代码块 static{ try{ //获取Mybatis获取sqlSessionFactory对象 String resource = "Mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); }catch (IOException e){ e.printStackTrace(); } } //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供 //了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。 public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
- 编写
-
pojo
实体类 –> 与数据库连接//POJO实体类 public class User { private int id; private String name; private String pwd; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } }
-
Dao/Mapper
接口package com.sjh.dao; import com.sjh.pojo.User; //Mapper接口 import java.util.List; public interface UserDao { List<User> getUserList(); }
-
接口实现类 —->由原来的
UserDaoImp
(JDBC
)转换为Mapper配置文件,配置文件就是JDBC
中的UserDaoImp
,UserDao
的实现<?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:命名空间 ,绑定对应的Dao/Mapper接口--> <mapper namespace="com.sjh.dao.UserDao"> <!--select查询语句, id对应的是接口的方法名,resultType:返回类型,实体类--> <select id="getUserList" resultType="com.sjh.pojo.User"> select * from mybatis.user </select> </mapper>
-
测试
import com.sjh.pojo.User; import com.sjh.until.MyBatisUntil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; public class UserDaoTest { @Test public void test(){ //第一步:获取SqlSession对象 SqlSession sqlSession = MyBatisUntil.getSqlSession(); //执行SQL UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> userList = mapper.getUserList(); for (User user : userList) { System.out.println(user); } //关闭SqlSession sqlSession.close(); } }
异常/错误
<!--异常一:接口未被注册--> org.apache.ibatis.binding.BindingException: Type interface com.sjh.dao.UserDao is not known to the MapperRegistry. <!--解决方案 在mapper.xml配置文件中配置一下内容--> <mappers> <mapper resource="com/sjh/dao/UserMapper.xml"/> </mappers> <!----------------------------------------------------------------------------------> <!--异常二:资源过滤问题,初始化异常失败,找不到UserMapper.xml--> org.apache.ibatis.exceptions.PersistenceException: Could not find resource com/sjh/dao/UserMapper.xml <!--解决方案:在build中配置resources,来防止我们资源导出失败问题,配置资源过滤--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
CRUD增删改查
- 编写接口
- 编写对应的
mapper.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">
<!--namespace:命名空间 ,绑定对应的Dao/Mapper接口-->
<mapper namespace="com.sjh.dao.UserMapper">
//编写接口
public interface UserMapper {
List<User> getUserList();
//查询数据
User getId(int id);
//增加数据
int getAdd(User user);
//删除数据
int delUser(int id);
//更改数据
int updateUser(User user);
}
-
增,删,改需要事务提交
//提交事务 sqlSession.commit(); //关闭 sqlSession.close();
-
增
<!--添加数据 insert:插入--> <!--id对应的是方法名,parameterType:参数类型--> <insert id="getAdd" parameterType="com.sjh.pojo.User"> insert into admin(id, name, pwd) values (#{id},#{name},#{pwd}) </insert> <----------------------------------------测试----------------------------------------> //添加数据 @Test public void getAdd(){ //第一步:获取SqlSession对象 SqlSession sqlSession = MyBatisUntil.getSqlSession(); //执行SQL UserMapper mapper = sqlSession.getMapper(UserMapper.class); int add = mapper.getAdd(new User(4, "王五", "121212")); if (add>0){ System.out.println("添加成功"); } sqlSession.commit(); sqlSession.close(); }
-
删
<!--删除数据 delete:删除--> <delete id="delUser" parameterType="int"> delete from admin where id = #{id} </delete> <--------------------------------------测试-----------------------------------------> //删除数据 @Test public void delUser(){ //获取SqlSession对象 SqlSession sqlSession = MyBatisUntil.getSqlSession(); //执行SQL语句 UserMapper mapper = sqlSession.getMapper(UserMapper.class); //删除id为4的数据 mapper.delUser(4); //提交事务 sqlSession.commit(); //关闭 sqlSession.close(); }
-
查
<!--根据id查询数据 select:查询--> <!--id对应的是方法名,resultType:返回类型,实体类. parameterType:参数类型--> <select id="getId" resultType="com.sjh.pojo.User" parameterType="int"> select * from admin where id = #{id} </select> <-----------------------------------------测试-------------------------------------> //根据id查询数据 @Test public void getId(){ //第一步:获取SqlSession对象 SqlSession sqlSession = MyBatisUntil.getSqlSession(); //执行SQL UserMapper mapper = sqlSession.getMapper(UserMapper.class); User id = mapper.getId(2); System.out.println(id); //关闭SqlSession sqlSession.close(); }
-
改
<!--更改数据 update:更改--> <update id="updateUser" parameterType="com.sjh.pojo.User"> update admin set name = #{name},pwd = #{pwd} where id = #{id} </update> <-----------------------------------------测试-------------------------------------> //更改数据 @Test public void updateUser(){ //第一步,获取SqlSession对象 SqlSession sqlSession = MyBatisUntil.getSqlSession(); //执行SQL语句 UserMapper mapper = sqlSession.getMapper(UserMapper.class); //操作数据库进行更改数据操作 mapper.updateUser(new User(4,"赵柳","121212")); //提交事务 sqlSession.commit(); //关闭 sqlSession.close(); }
1.2 ☆万能的Map
- 编写接口
//更改数据
int updateUser02(Map<String,Object> map);
- 编写对应的
mapper.xml
中的SQL
语句
<!--更改数据 update:更改 parameterType:参数类型-->
<update id="updateUser02" parameterType="Map">
update mybatis.admin set pwd = #{UserPwd} where id = #{UserId}
</update>
- 测试
@Test
public void updateUser02(){
//获取SqlSession对象
SqlSession sqlSession = MyBatisUntil.getSqlSession();
//执行SQL
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//操作数据库更改数据,获取Map集合
Map<String, Object> map = new HashMap<String, Object>();
map.put("UserId",3);
map.put("UserPwd",111222);
mapper.updateUser02(map);
//提交事务
sqlSession.commit();
//关闭
sqlSession.close();
}
1.3 模糊查询
-
与上面的都一样,只有查询语句有所改变
<!--方式一:会发生SOL注入--> select * from mybatis.admin where name like "%"#{value}"%"
-
java
代码执行时,传递通配符%%//方式二: mapper.getUserLike("%李%")
Mybatis
核心配置文件优化
configuration
(配置)default
(默认)transactionManager
(事务管理器)有两种:JDBC
(默认)和MANAGEDdataSource
(数据源) 连接池:POOLED(默认)properties
(属性)settings
(设置)typeHandlers
(类型处理器)objectFactory
(对象工厂)plugins
(插件)environments
(环境配置)environment
(环境变量)databaseIdProvider
(数据库厂商标识)mappers
(映射器)
原配置文件(resources/mybatis-config.xml
)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
<!--环境-->
<environments default="development">
<environment id="development">
<!--事务管理-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="825520"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/sjh/dao/UserMapper.xml"/>
</mappers>
</configuration>
现核心配置文件
- 将原核心配置文件分为核心配置文件和properties文件
resources/db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username=root
password=825520
核心配置文件
config.xml
文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
<!--引入外部配置文件-->
<properties resource="db.properties"/>
<!--环境-->
<environments default="development">
<environment id="development">
<!--事务管理-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/sjh/dao/UserMapper.xml"/>
</mappers>
</configuration>
优点;
- 简化代码
- 灵活
- 如果两个文件有同一个字段,优先使用外部文件
typeAliases
标签(类型别名)
- 方式一:将
Mapper.xml
文件中resultType
属性放到config.xml
文件中type属性并取别名
<!--config.xml文件-->
<typeAliases>
<!--type:实体类 alias:别名-->
<typeAlias type="com.sjh.pojo.User" alias="User"/>
</typeAliases>
<!--Mapper.xml文件-->
<!--根据id查询数据-->
<select id="getId" resultType="User" parameterType="int">
select * from mybatis.admin where id = #{id}
</select>
- 方式二: 扫描实体类的包,它的默认别名就为这个类的类名首字母小写name→
resulType
<!--config.xml文件-->
<typeAliases>
<!--type:实体类 alias:别名-->
<package name="com.sjh.pojo" /> ←------
</typeAliases>
<!--Mapper.xml文件-->
<!--根据id查询数据-->
<select id="getId" resultType="user" parameterType="int"> ←------
select * from mybatis.admin where id = #{id}
</select>
方式一与方式二的比较:
-
当实体类比较少的时候使用方式一,如果实体类十分多建议使用方式二
-
方式一可以自定义别名,方式二则不行,如果非要自定义别名,则需要在实体类中添加注解**@Alias**
//POJO实体类 @Alias("hello") public class User { .......... }
设置
Mybatis
中极为重要的调整设置,它们会改变Mybatis
的运行时行为
- 其他设置
typeHandlers
(类型处理器)objectFactory
(对象工厂)plugins
(插件)
映射器(mapper)
MapperRegistry
:注册绑定我们的Mapper文件
- 方式一:【推荐使用】
- mapper标签
<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
<mappers>
<mapper resource="com/sjh/mapper/UserMapper.xml"/>
</mappers>
- 方式二:使用class标签绑定注册
- mapper标签
<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
<mappers>
<mapper class="com.sjh.mapper.UserMapper"/>
</mappers>
注意点:接口和它的mapper配置文件必须同名同包
- 方式三:使用扫描包进行注入绑定.
- package标签
<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
<mappers>
<package name="com.sjh.mapper"/>
</mappers>
注意点:接口和它的mapper.xml
配置文件必须同名同包
生命周期与作用域
生命周期和作用域是至关重要的,错误的使用会导致非常严重的并发问题
`
SqlSessionfactoryBuilder
- 一旦创建了
SqlSessionFactory
就不需要它了 - 局部变量
SqlSessionfactory
:
- 可以想象为:数据连接池
- 一旦创建就应该在应用的运行期间一直存在,没有任何理由丢弃或重新创建另一个实例
SqlSessionFactory
的最佳作用域是应用作用域
SqlSession
- 连接到连接池的一个请求
- 线程不安全,用完需要关闭,否则资源被占用
结果集映射(解决属性名与数据库字段名不一致问题)
数据库字段
项目属性字段
解决方案一
<!--UserMapper.xml文件-->
<!--取别名-->
<select id="getId" resultType="hello" parameterType="int">
select id,name,pwd as password from admin where id = #{id}
</select>
解决方案二
<!--UserMapper.xml文件-->
<!--resultMap标签-->
②<resultMap id="UserMapper" type="com.sjh.pojo.User">
<!--column:列,数据库中字段。property:属性字段-->
<result column="pwd" property="password"/>
</resultMap>
① <!--select查询语句, id对应的是方法名,resultType:返回类型-->
<select id="getUserList" resultMap="UserMapper">
select * from mybatis.admin
</select>
日志
-
日志工厂
LOG4J
【掌握】Log4j
Log4j 2
SLF4J
Apache Commons Logging
JDK logging
STDOUT_LOGGING
【掌握】
<!--mybatis核心配置文件,STDOUT_LOGGING:标准日志--> <settings> <!--name:设置日志,value:日志类型--> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> ---------------------------------------------------------------------- <!--LOG4J日志--> <settings> <!--name:设置日志,value:日志类型--> <setting name="logImpl" value="LOG4J"/> </settings>
LOG4J
日志
什么是LOG4J
- 是Apache的一个开源项目
- 可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等
- 也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
- 可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码
-
导入依赖
<!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
-
在resources文件夹下建立
log4j.properties
文件- 网上搜索
LOG4J
配置文件
- 网上搜索
-
设置配置文件
<!--mybatis核心配置文件--> <!--LOG4J日志--> <settings> <!--name:设置日志,value:日志类型--> <setting name="logImpl" value="LOG4J"/> </settings>
分页
为什么要是用分页
- 减少数据的处理量
Limit实现分页
pageSize:每页显示;startIndex:从第几个开始查
语法:select * from user limit startIndex,pageSize;
例子:select * from user limit 4;#从零开始,每页四个
注解:
用注解代替UserMapper.xml
配置文件,简化代码,当复杂的SQL
语句时不建议使用
@Param
:放于参数前,当参数超过两个时,必须写此参数id01
- 基本类型的参数或者String类型,需要加上
- 引用类型不需要加
- 如果只有一个基本类型的话,可以忽略,但建议加上
- 在
SQL
中引用的就是这里的@Param()
中设定的属性名
//根据ID查找数据
@Select("select * from admin where id=#{id}")
User getId(@Param("id01") int id);
----------------------------------------------------------------------
<!--根据id查找数据-->
<select id="getId" resultType="com.sjh.pojo.User">
select * from admin where id = #{id01}
</select>
CURD增删查改
<!--前提-->
<!--核心配置文件中绑定接口-->
<mappers>
<mapper resource="com/sjh/dao/UserMapper.xml"/>
</mappers>
-
增
public interface UserMapper { //添加数据 @Insert("insert into admin(id, name, pwd) values (#{id},#{name},#{pwd})") int getAdd(User user); }
-
删
public interface UserMapper { //删除数据 @Delete("delete from admin where id= #{id}") int getDelete(int id); }
-
查
public interface UserMapper { //根据ID查找数据 @Select("select * from admin where id =#{id}") User getId(int id); }
-
改
public interface UserMapper { //更改数据 @Update("update admin set name = #{name},pwd = #{pwd} where id = #{id}") int getUpdate(User user); }
Lombok
插件:不建议经常使用
- 使用注解代替编写get,set,equals等代码
使用步骤:
-
在IDEAL中安装
Lombok
插件 -
在项目中导入
Lombok
的jar包<!--Lombok插件的Jar包--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency>
-
安装完成后就可以使用注解:用于实体类(
POJO
)类名上
@Data
:可自动生成:有参无参,get/set方法,equals,hashcode
,toString
….
@ToString
:可自动生成toString
方法
@getter
:可自动生成get方法
@setter
:可自动生成set方法
@AllArgsConstructor
:可自动生成有参构造器
@NoArgsConstructor
:可自动生成无参构造器
优点:
- 通过注解形式自动生成构造器get/set等方法,提高了开发效率
- 简化代码
缺点:
- 不支持多种参数构造器的重载
- 降低了源码的可读性和完整性,降低了阅读源码的舒适度
缓存:
存在内存中的临时数据
- 一级缓存
- 二级缓存
一级缓存:又称本地缓存,默认是开启的,只有一次SqlSession
中有效,也就是拿到连接到关闭连接这个区间段
一级缓存失效情况:
- 查询不同的数据
- 进行增删改操作时,可能改变原来的数据,会刷新缓存
- 查询不同的**
Mapper.xml
** - 手动清理缓存**
clearCache()方法
**
二级缓存:
- 又称全局缓存,一级缓存作用太低了,所以诞生了二级缓存
- 基于
namespace
级别的缓存,一个命名空间,对应一个二级缓存
步骤:
-
开启缓存前提需设置进行一下两个操作
<!--开启缓存,mybatis核心配置文件中--> <setting name="cacheEnabled" value="true"/> <!--true:开启(默认),false:关闭-->
<!--在当前Mapper.xml文件中使用二级缓存--> <cache/> <!------------------------------------------------------> <!--也可以设置二级缓存属性--> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
单个的
SQL
操作中也可以设置缓存<!--查询信息,useCache="true"默认开启缓存--> <select id="getUserList" resultType="com.sjh.pojo.User" useCache="true"> select * from admin </select> 改<update/> 增<insert/> →只有<flushCache="false/true">刷新缓存操作 删<delete/>
缓存过程图
自定义缓存Ehcshe
(使用较少,现较多使用Redis
缓存)
- 开源的
java
分布式缓存 - 主要面向通用缓存,
javaEE
和轻量级容器, - 它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序
- 一个
gzip
缓存servlet
过滤器,支持REST
和SOAP api
等特点