目录
十一、动态SQL环境搭建、IF语句、常用标签、Foreach语句
gitee仓库地址:https://gitee.com/inandout/mybatis/tree/dev/
一、什么是mybatis
1、官网
- Mybatis是一款优秀的持久层框架
- Mybatis支持定制化sql、存储过程、高级映射
- Mybatis避免了几乎所有的JDBC代码、手动设置参数、获取结果集操作
- Mybatis可以使用简单的xml、注解 来配置和映射 原生类型、接口、pojo(普通老式java对象) 为数据库中的记录
2、百度百科
MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。
单独使用mybatis是有很多限制的(比如无法实现跨越多个session的事务),而且很多业务系统本来就是使用spring来管理的事务,因此mybatis最好与spring集成起来使用。
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件。易于学习,易于使用。通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
- 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的ORM字段关系映射。
- 提供对象关系映射标签,支持对象关系组建维护。
- 提供xml标签,支持编写动态sql。
开源、maven项目
无关联依赖,只需要导入1个包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
3、持久层
数据持久化:就是将程序的数据在瞬时状态和持久状态之间转化的过程。
- 内存:断电即丢失(太贵了)
- 硬盘:断电不丢失
持久层:Dao层、Service层、Controller层
- 完成持久化工作的代码块
- 层是界限明显的
4、从XML 中构建 SqlSessionFactory
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。后面会再探讨 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>
<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="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
注意 XML 头部的声明,它用来验证 XML 文档的正确性。
二、第一个mybatis程序
1、创建mybatis数据库
create database mybatis;
创建user表
CREATE TABLE `user` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='用户表';
2、创建mybatis工程
本地创建maven工程,推送gitee仓库。
在VCS选项栏里,选择Git,点击create a git project,将本项目设为git仓库
commit -> push
choose a remote url https://gitee.com/inandout/mybatis
创建子项目,继承了父项目的依赖
3、编写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>
<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=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
4、编写Mapper层,增删改查实现
查全部、查单个
<select id="getUserList" resultType="com.kuang.pojo.User">
select *
from mybatis.User
</select>
<select id="selectUserById" parameterType="int" resultType="com.kuang.pojo.User">
select *
from mybatis.User
where id = #{id}
</select>
新增
<insert id="insertUser" parameterType="com.kuang.pojo.User">
insert into mybatis.User
(id, name, password)
values (#{id}, #{name}, #{password})
</insert>
修改
<update id="updateUser" parameterType="com.kuang.pojo.User">
update mybatis.User
set name =#{name},
password =#{password}
where id = #{id}
</update>
删除
<delete id="deleteUser" parameterType="int">
delete
from mybatis.User
where id =
#{id}
</delete>
5、编写Dao层
package com.kuang.dao;
import com.kuang.pojo.User;
import java.util.List;
public interface UserDao {
List<User> getUserList();
User selectUserById(int id);
int insertUser(User user);
int updateUser(User user);
int deleteUser(int id);
}
6、编写Test层,执行测试,输出结果
@Test
public void insertUser() {
// 开启连接
try (SqlSession sqlSession = MybatisUtils.getSqlSession()) {
UserDao mapper = sqlSession.getMapper(UserDao.class);
User user = new User();
user.setName("测试1");
user.setPassword("324");
// 调用dao的接口
int i = mapper.insertUser(user);
// 打印结果
System.out.println(i);
// 提交事务,否则数据库里不会有值
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
}
// 关闭session
}
三、Map和模糊查询扩展
1、万能的Map
入参为User时,所有参数都得传,而将入参改为Map,就可以只传某个参数
<select id="selectUserByIdAndName" parameterType="map" resultType="com.kuang.pojo.User">
select *
from mybatis.User
where id = #{id}
and name = #{name}
</select>
<insert id="insertUserByMap" parameterType="map">
insert into mybatis.User
(name, password)
values (#{name}, #{password})
</insert>
2、模糊查询
①Java代码执行的时候,传递通配符%%
List<User> userList = mapper.getUserListLike("%T%");
②在sql拼接中使用通配符
select * from mybatis.User where name like "李" or 1=1
sql注入问题
${}无法防止sql注入,而#{}可以防止注入
四、配置之属性优化、别名优化、映射器说明
核心配置文件:mybatis-config.xml
1、环境配置
MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推,记起来很简单:
- 每个数据库对应一个 SqlSessionFactory 实例
为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。可以接受环境配置的两个方法签名是:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
2、属性优化
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:
因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。
propertie必须放在第一个标签,因为标签具有顺序。
3、别名优化
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
<typeAliases>
<typeAlias type="com.kuang.pojo.User" alias="User"/>
</typeAliases>
各种设置总览:
4、映射器说明
五、生命周期和作用域、Mybatis执行流程剖析
1、生命周期和作用域
官方文档
2、Mybatis执行流程剖析
debug+源码分析
configuration配置文件解析结果
Executor
mapper创建
六、ResultMap结果集映射
1、基础结果映射
resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
<resultMap id="userResultMap" type="User">
<id property="id" column="id"/>
<result property="userName" column="name"/>
<result property="passWord" column="password"/>
</resultMap>
<select id="getUserList" resultMap="userResultMap">
select *
from mybatis.User
</select>
<select id="selectUserById" parameterType="int" resultType="com.kuang.pojo.User">
select id as "userId",
name as "userName",
password as "passWord"
from mybatis.User
where id = #{id}
</select>
在学习了上面的知识后,你会发现上面的例子没有一个需要显式配置 ResultMap,这就是 ResultMap 的优秀之处——你完全可以不用显式地配置它们。
2、高级结果映射
第十节,association、collection。
七、日志工厂、log4j讲解
1、日志工厂
如果一个数据库操作出现了异常,我们需要排错,日志就是最好的助手!
- 基本的方法:sout、debug
- 现在的办法:日志工厂
LOG4J Apache日志输出
STDOUT_LOGGING 标准日志输出
2、LOG4J
百度百科
- Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;
- 我们也可以控制每一条日志的输出格式;
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
- 最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
导入LOG4J的包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
配置log4j.properties文件
在代码里添加日志打印
static Logger logger = Logger.getLogger(UserTest.class);
@Test
public void testLog4j() {
logger.info("进入了”testLog4j“方法");
八、Limit实现分页、RowBounds分页
1、Limit实现分页
通过在sql代码里拼接limit的值来实现
<select id="getUserByLimit" parameterType="map" resultType="com.kuang.pojo.User">
select *
from mybatis.User limit #{startIndex},#{pageSize}
</select>
2、RowBounds分页
List<Object> objects = sqlSession.selectList("com.kuang.dao.UserDao.getUserList", null, new RowBounds(1, 2));
直接使用mybatis自带的原生方法
3、pageHelper
最热门的分页插件,具体请查看百度
九、使用注解开发、注解增删改查、Lombok的使用
1、增删改查
@Select("select * from mybatis.User")
List<User> getUserList();
@Select("select * from mybatis.User where id = #{id}")
User getUserById(@Param("id") int id);
@Insert("insert into mybatis.User (id,name,password) values (#{id},#{name},#{password})")
int addUser(User user);
@Update("update mybatis.User set name = #{name}, password = #{password}) where id = #{id}")
int updateUser(User user);
@Delete("delete from mybatis.User where id = #{id}")
int deleteUser(@Param("id") int id);
2、@Param注解
- 基本数据类型要加,引用类型不用加
- 只有一个参数时,可以不加
3、Lombok的使用
①安装插件
②导入jar包
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
</dependency>
③使用Lombok注解
Data
整合了Getter、Setter、ToString、EqualsAndHashCode、RequiredArgsConstructor注解。
Getter
快速构建Getter方法。
Setter
快速构建Setter方法。
ToString
EqualsAndHashCode
快速进行相等判断。
十、复杂查询环境搭建、多对一的处理、一对多的处理
1、建立复杂查询环境
建立student表,teacher表,和user表整体结构完全一样
2、多对一处理
按照查询嵌套处理
<!--按照查询嵌套处理-->
<select id="getStudentList" resultMap="StudentTeacher">
select *
from mybatis.student
</select>
<resultMap id="StudentTeacher" type="com.kuang.pojo.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂的属性,需要单独处理-->
<association property="teacher" column="tid" javaType="com.kuang.pojo.Teacher" select="getTeacherList"/>
</resultMap>
<select id="getTeacherList" resultType="com.kuang.pojo.Teacher">
select *
from mybatis.teacher
where id = #{id}
</select>
按照结果嵌套处理
<!--按照结果嵌套处理-->
<select id="getStudentList2" resultMap="StudentTeacher2">
select s.id sid, s.name sname, t.name tname, t.age tage
from mybatis.student s,
mybatis.teacher t
where s.tid = t.id
</select>
<resultMap id="StudentTeacher2" type="com.kuang.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<!--复杂的属性,需要单独处理-->
<association property="teacher" javaType="com.kuang.pojo.Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
3、一对多处理
按照结果嵌套处理
关联association
按照查询嵌套处理
集合collection
十一、动态SQL环境搭建、IF语句、常用标签、Foreach语句
1、搭建环境
创建博客表,插入数据
CREATE TABLE `blog` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`title` varchar(100) DEFAULT NULL COMMENT '标题',
`author` varchar(100) DEFAULT NULL COMMENT '作者',
`createTime` date DEFAULT NULL COMMENT '创建时间',
`views` int(11) DEFAULT NULL COMMENT '点赞数',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='博客表';
2、IF语句
<select id="getBlogList" parameterType="com.kuang.pojo.Blog" resultType="com.kuang.pojo.Blog">
select *
from mybatis.blog
where 1=1
<if test="title !=null">
and title=#{title}
</if>
<if test="author !=null">
and author=#{author}
</if>
</select>
3、常用标签
choose标签
<select id="findActiveBlogLike" resultType="com.kuang.pojo.Blog">
select *
from mybatis.blog
where 1=1
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null">
AND author like #{author}
</when>
<otherwise>
AND views = #{views}
</otherwise>
</choose>
</select>
trim标签
<select id="findActiveBlogWithTitleLike" resultType="com.kuang.pojo.Blog">
select *
from mybatis.blog
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="title !=null">
and title like #{title}
</if>
<if test="author !=null">
and author like #{author}
</if>
</trim>
</select>
4、Foreach语句
<select id="selectNameIn" resultType="com.kuang.pojo.Blog">
SELECT *
FROM mybatis.blog b
WHERE b.title in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
十二、缓存原理、一二级缓存、自定义缓存Ehcache
Mybatis包含一个非常强大的查询缓存特性,他可以非常方便的定制和配置缓存,缓存可以极大的提高查询的效率。
Mybatis系统中默认定义了两种缓存:一级缓存、二级缓存
- 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
- 二级缓存需要手动配置和开启,他是namespace级别的缓存
- 为了提高扩展性,Mybatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
1、缓存原理
①什么是缓存Cache?
- 存在内存中的临时数据。
- 将用户经常查询的数据放在缓存中,这样用户查询时就不用去磁盘上查询,可以直接从缓存中拿到,从而提高查询效率,解决了高并发系统的性能问题。
②为什么要使用缓存?
- 减少和数据库的交互次数,减少系统开销,提高系统效率。
③什么样的数据能使用缓存?
- 经常查询且不经常改变的数据。
2、一级缓存
一级缓存也叫本地缓存
- 与数据库同一次会话期间查询到的数据会放在本地缓存中
- 以后如果需要获取相同的数据,直接从缓存中拿,不用再从数据库查
默认情况下,启用了本地的会话缓存,它仅仅对一个sqlSession会话中的数据进行缓存。
缓存失效的场景
1、SqlSession调用了close()方法后,就失效了
2、
3、查询不同的mapper.xml
4、SqlSession.clearCache()
3、二级缓存
二级缓存也叫全局缓存,因为一级缓存得到作用域太低了,所以诞生了二级缓存。
他是基于nameSpace级别的缓存,一个名称空间对应一个二级缓存。
- 一个session查询一条数据,这个数据就会被放在一级缓存里;
- 这个session关闭了,我们想让他从一级缓存转移到二级缓存中;
- 新的sesssion查询数据,就可以从二级缓存中获取结果;
- 不同的mapper查询出的数据会放在各自的缓存map中;
开启方式:
①在核心配置文件里,通过设置开启缓存
②在mapper.xml里,通过标签开启缓存
<!-- 开启二级缓存 -->
<cache/>
在代码里进行测试
@Test
public void cache() {
// 开启2个会话
SqlSession sqlSession = MybatisUtils.getSqlSession();
SqlSession sqlSession2 = MybatisUtils.getSqlSession();
List<String> list = new ArrayList<>();
list.add("花开伊吕波");
list.add("测试");
BlogDao mapper = sqlSession.getMapper(BlogDao.class);
List<Blog> userList = mapper.selectNameIn(list);
// 同一个mapper里,一个会话查询关闭了,会保存到二级缓存中
sqlSession.close();
// 看是查1次,还是2次
BlogDao mapper2 = sqlSession2.getMapper(BlogDao.class);
List<Blog> userList2 = mapper2.selectNameIn(list);
sqlSession2.close();
}
提示缓存命中
4、自定义缓存Ehcache
东亚多数用mybatis,国外多数用hibernate和JPA
Java的缓存技术:Ehcache与Redis比较
综上所述,Ehcache适合本地缓存和单机环境下的简单应用场景,提供快速的内存访问。而Redis更适合分布式缓存和高性能、高并发的需求,提供了更多高级功能和数据持久化选项。在选择时,需要根据实际需求和项目特点进行综合考虑。
实现自定义缓存的多种方式:
①导包、然后配置别人的Cache实现
<!-- Ehcache缓存 -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.0</version>
</dependency>
②自己实现Cache接口
package com.kuang.utils;
import org.apache.ibatis.cache.Cache;
public class MyCache implements Cache {
@Override
public String getId() {
return null;
}
@Override
public void putObject(Object key, Object value) {
}
@Override
public Object getObject(Object key) {
return null;
}
@Override
public Object removeObject(Object key) {
return null;
}
@Override
public void clear() {
}
@Override
public int getSize() {
return 0;
}
}