MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了[google code](https://baike.baidu.com/item/google code/2346604),并且改名为MyBatis 。2013年11月迁移到Github。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
帮助文档
使用其,需要引入依赖
(x.x.x 指版本 在maven仓库寻找合适版本)
maven
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>x.x.xversion>
dependency>
//利用jdbc,完成新增的功能
private static void method2() throws Exception{
//1,注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2,获取数据库的连接
//数据传输协议 数据库的ip 端口号 数据库名
String url = "jdbc:mysql://localhost:3306/lxb";
Connection c = DriverManager.getConnection(url,"root","root");
//3,获取传输器
Statement s = c.createStatement();
//4,利用传输器执行 增删改的SQL
//executeUpdate()用来执行增删改的SQL,只返回影响行数
int rows = s.executeUpdate(
"INSERT INTO emp(ename,job) VALUES('rose','副总')");
//5,释放资源
//r.close();//结果集
s.close();//传输器
c.close();//连接
}
在没使用mybatis时,我们一般用JDBC连接数据库进行持久化操作。
但太过繁琐,开发成本高,还需手动关闭,所以这些繁琐的代码被封装在mybatis使开发者只需要关注 SQL 本身,但在代码执行效率上JDBC比mybatis快。
对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。如今已有很多免费和付费的ORM产品,而有些程序员更倾向于创建自己的ORM工具。
延伸:
1. 对象与数据库中的表一一对应
2. 对象的属性与表中的字段一一对应
3. 其中的映射应该由程序自动完成.无需人为干预.
4. mybatis基于ORM设计思想实现了以对象的方式操作数据库
了解:
········mybatis的ORM不完整,只实现了结果集的映射。sql语句还需自己写,所以mybatis也被称为半自动化ORM框架。
数据持久化
为什么要有持久化?
因为内存有断电及失的特性。但有些对象我们不能将其丢失,所有出现持久化。
思路
搭建数据库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aniFX4Un-1624001352346)(C:\Users\李晓冰\AppData\Roaming\Typora\typora-user-images\image-20210615143740211.png)]
创建maven项目
导入依赖(版本号可以去 MVN 进行查找)
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.7version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.26version>
dependency>
编写mybatis的核心配置文件 在resources中创建xml文件 mybatis-config
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)
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="mapper.xml"/>
mappers>
configuration>
在resource创建mapper包,在此包中根据需要创建与dao成对应的XXXmapper.xml文件
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nuc.dao.UserDao">
<select id="getAll" resultType="User类的完整路径:包名.类名">
/具体的sql语句/
select * from usertest
select>
mapper>
pojo层
写入一个user类
dao层----与mapper对应 要在namespace写入对应全类名
import com.nuc.pojo.User;
import java.util.List;
public interface UserDao {
List<User> getAll();
Service层
ServiceImpl层
public class Test {
public static void main(String[] args) throws Exception {
//加载配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//得到sqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory build = builder.build(reader);
//得到sqlSession
SqlSession sqlSession = build.openSession();
//操作sql 传入参数:类名.方法名
List<User> list = sqlSession.selectList("com.nuc.dao.UserDao.getAll");
//遍历
for (User u : list){
System.out.println(u);
}
//关闭资源
sqlSession.close();
reader.close();
}
}
增加语句;
<mapper namespace="com.nuc.dao.UserDao">
<select id="getAll" resultType="com.nuc.pojo.User" >
select * from USER
select>
mapper>
步骤 :
public interface UserMapper {
//插入用户
public void addUser(User user);
}
编写对应的mapper中的sql语句
<insert id="addUser" parameterType="com.nuc.pojo.User">
insert into user (id,name,password) values (#{id}, #{name}, #{password})
insert>
3. 测试
@Test
public void test2() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User(1,"望埠","123");
mapper.addUser(user);
//增删改一定要提交事务
sqlSession.commit();
//关闭sqlSession
sqlSession.close();
}
<select id="getAll" resultType="com.nuc.pojo.User">
select * from USER
select>
<update id="updateUser" parameterType="User">
update user set name=#{name},pwd=#{pwd} where id=#{id}
update>
<delete id="delectUser" parameterType="java.lang.String">
delete from user where name = #{name}
delete>
注意 增删改一定要提交事务:sqlSession.commit();
上述会报错,会将其识别为标签符号。我们可以用转义字符
在XML中,需要转义的字符有:
(1)& &;
(2)< <;
(3)> >;
(4)" ";
(5)' &apos;
例如:
select * from demo_user where age>=#{minAge} and age<#{maxAge}
如果sql中有大量转义字符,建议使用转义标签
语法:
=#{minAge} and age<#{maxAge}]]>
当我们的实体类,或数据库中的表参数过多,我们应该使用map
<insert id="addUser2" parameterType="map">
insert into user (id,name)
values (#{userid},#{username});
insert>
测试:
@Test
public void test02() throws IOException {
//加载配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//得到sqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory build = builder.build(reader);
//得到sqlSession
SqlSession sqlSession = build.openSession();
Map<String,Object> map = new HashMap<>();
map.put("userid",5);
map.put("username", "jj");
sqlSession.insert("com.nuc.dao.UserDao.addUser2",map);
sqlSession.commit();
//关闭sqlSession
sqlSession.close();
}
注意 :提交事务
Map传递参数,直接在sql中取出key即可! 【parameter=“map”】
对象传递参数,直接在sql中取出对象的属性即可! 【parameter=“Object”】
只有一个基本类型参数的情况下,可以直接在sql中取到
多个参数用Map , 或者注解!
集合参数写法 list/mapper/array
如:查询集合内的id对应的信息
语法:
List<DemoUser> findList(List<Integer> list);
<select id="findList" resultType="com.demo1.pojo.DemoUser" parameterType="java.util.List">
select * from demo_user where id in <foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
foreach>
1 在java代码执行时,传递通配符
接口:
List<User> selectlike(String value);
mapper
<select id="selectlike" resultType="com.nuc.pojo.User" parameterType="java.lang.String">
select * from user where name like #{value}
select>
测试:
@Test
public void test() throws IOException {
//加载配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//得到sqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory build = builder.build(reader);
//得到sqlSession
SqlSession sqlSession = build.openSession();
List<User> list = sqlSession.selectList("com.nuc.dao.UserDao.selectlike","%李%");
for (User user : list) {
System.out.println(user.toString());
}
//关闭sqlSession
sqlSession.close();
}
2.在sql拼接使用通配符
<select id="selectlike" resultType="com.nuc.pojo.User" parameterType="java.lang.String">
select * from user where name like “%”#{value}“%”
select>
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
configuration(配置)
记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
transactionManager>
<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>
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]")
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]")
mybatis默认事务管理器jdbc 连接池 POOLED
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置:
步骤:
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8&appserverTimezone=UTC
username =root
password = root
2. 在核心配置文件映入
<properties resource="db.properties">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>
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。如mapper中返回值类型的全限定类名
<typeAliases>
<typeAlias type="com.nuc.pojo.User" alias="user">typeAlias>
typeAliases>
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases>
<package name="com.nuc.pojo" />
typeAliases>
扫描实体类的包,他的默认别名就是这个类的类名,首字母小写
但若在实体类上有注解,则别名为其注解值。见下面的例子:
@Alias("author")
public class Author {
...
}
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。
设置setting详情
MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:///
形式的 URL),或类名和包名等。
现在主要用以下方法实现
第一种
<mappers>
<mapper resource="com/nuc/Mapper/UserMapper.xml"/>
<mapper resource="com/nuc/Mapper/PersonMapper.xml"/>
mappers>
第二种
<mappers>
<package name="com.nuc.pojo"/>
mappers>
第三种
<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
mappers>
**注意点:**第二种和第三种方法
作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder:
一旦创建了SqlSessionFactory,就不再需要它了
局部变量
SqlSessionFactory:
说白了就可以想象为:数据库连接池
SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建一个实例。因此SqlSessionFactory的最佳作用域是应用作用域(ApplocationContext)。
最简单的就是使用单例模式或静态单例模式。
SqlSession:
连接到连接池的一个请求
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
用完之后需要赶紧关闭,否则资源被占用!
当累的属性为:
private int id;
private String name;
private String password;
数据库字段名为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nbzNcput-1624001352349)(C:\Users\李晓冰\AppData\Roaming\Typora\typora-user-images\image-20210616184127087.png)]
用User接收无法接收到password属性
解决 方法:
起别名
<select id="getAll" resultType="aaa">
select id,name,pwd as password from USER
select>
使用resultMap
resultMap是一个结果集映射
<resultMap id="UserMap" type="User">
<result column="pwd" property="password">result>
resultMap>
<select id="getUserList" resultMap="UserMap">
select* from USER
select>
resultMap 元素是 MyBatis 中最重要最强大的元素。
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
ResultMap 的优秀之处——你完全可以不用显式地配置它们。
如果这个世界总是这么简单就好了(尤其是找对象)
如果一个数据库操作,出现了异常,我们需要排错,日志就是最好的纠错助手
曾经:sout输出、debug
现在:日志工厂
在MyBatis中具体使用哪一个日志实现,在设置中设定
STDOUT_LOGGING
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
注意 是logImpl ,Impl的i是大写的,不能有一点错,也不能有空格。
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
使用
2.1 导包
地址
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
在resources中配置log4j.properties(百度)
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/lxb.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
<settings>
<setting name="logImpl" value="LOG4J"/>
settings>
2.4 在要使用log4j的類中使用
import org.apache.log4j.Logger;
import org.junit.jupiter.api.Test;
public class UserTest {
static Logger logger = Logger.getLogger(UserTest.class); //括號内跟本类的。class
@Test
public void test(){
logger.info("info: 测试log4j");
logger.debug("debug: 测试log4j");
logger.error("error:测试log4j");
}
}
运行完后生成log4j文件
1. 使用Limit分页
SELECT * from user limit startIndex,pageSize
下面是每页显示4个 从0开始查
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X97QQPHK-1624001352350)(C:\Users\李晓冰\AppData\Roaming\Typora\typora-user-images\image-20210616204351239.png)]
# 相当于SELECT * from user limit 0,3
SELECT * from user limit 3
2. 使用rowbounds分页
不再使用SQL实现分页,通过java代码实现
接口
List getUserByRowBounds();
mapper
<select id="getUserByRowBounds">
select * from user
select>
测试
@Test
public void getUserByRowBounds(){
//加载配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//得到sqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory build = builder.build(reader);
//得到sqlSession
SqlSession sqlSession = build.openSession();
//RowBounds实现 从下表一开始,每页显示2个
RowBounds rowBounds = new RowBounds(1, 2);
//通过Java代码层面实现分页
List<User> userList = sqlSession.selectList("com.kaung.dao.UserMapper.getUserByRowBounds", null, rowBounds);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
3.通过插件
mybatis分页插件pageHelper
链接
使用说明文档
说明文档
面向接口开发
三个面向区别
public interface UserDao {
@select("select * from user")
List<User> getAll();
}
2. 在核心配置文件绑定接口
<mappers>
<mapper class="com.nuc.dao.UserDao">mapper>
mappers>
//加载配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//得到sqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory build = builder.build(reader);
//得到sqlSession
SqlSession sqlSession = build.openSession();
UserDao mapper= sqlSession.getMapper(UserDao.class);
List<User> list = mapper.getAll();
for (User user : list) {
System.out.println(user.toString());
}
//关闭sqlSession
sqlSession.close();
本质:反射机制实现
底层:动态代理
我们可以在工具类创建时自动实现提交事务
//方法存在多个参数,所有的参数前面必须加上@Param("id")注解
@Delete("delete from user where id = ${uid}")
int deleteUser(@Param("uid") int id);
Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法。官方地址:,github地址:
idea使用步骤
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.20version>
<scope>providedscope>
dependency>
能使用的注解
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@Data 生成无参构造 set和get方法 hashcode,equals 和tostring
@AllArgsConstructor 生成所有的有参构造,但会失去默认生成的无参构造,要与@NoArgsConstructor(生成无参构造)配合
一个老师关联多个学生------一对多
多个学生对应一个老师-------多对一
查询结果在mapper中较复杂,用高级结果映射
结果映射(resultMap)
constructor
- 用于在实例化类时,注入结果到构造方法中
idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
arg - 将被注入到构造方法的一个普通结果
id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
result – 注入到字段或 JavaBean 属性的普通结果
association
– 一个复杂类型的关联;许多结果将包装成这种类型
- 嵌套结果映射 – 关联可以是
resultMap
元素,或是对其它结果映射的引用collection
一个复杂类型的集合
- 嵌套结果映射 – 集合可以是
resultMap
元素,或是对其它结果映射的引用discriminator使用结果值来决定使用哪个resultMap
case
基于某些值的结果映射
嵌套结果映射 –
case
也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射
<!--比如学生表里有学生id,姓名,老师id 查出其信息 老师应显示name-->
@Data
public class Student {
private int id;
private String name;
private int tid;
//学生需要关联一个老师
private Teacher teacher;
}
1.按照查询嵌套处理
<select id="getStudent" resultMap="StudentTeacher">
select * from student
select>
<resultMap id="StudentTeacher" type="student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
resultMap>
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id}
select>
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid , s.name sname, t.name tname
from student s,teacher t
where s.tid=t.id
select>
<resultMap id="StudentTeacher2" type="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="teacher">
<result property="name" column="tname">result>
association>
resultMap>
mysql中多对一的查询方式:子查询,联表查询
同样的例子,但环境 搭建是teacher有所改变------查询指定老师下的老师及学生信息
@Data
public class Teacher {
private int id;
private String name;
//一个老师拥有多个学生
private List<Student> students;
}
<select id="getTeacher" resultMap="StudentTeacher">
SELECT s.id sid, s.name sname,t.name tname,t.id tid FROM student s, teacher t
WHERE s.tid = t.id AND tid = #{tid}
select>
<resultMap id="StudentTeacher" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
collection>
resultMap>
SELECT * from teacher where id=#{id}select>
<resultMap id="StudentTeacher2" type="Teacher">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<collection property="students" javatype="ArrayList"oftype="Student"
select="studentbytid " column="id">
collection>
resultMap>
<select id="studentbytid" resultType="Student">
select * from student where tid=#{id}
select>
if----用以拼接sql:
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from blog
where 1=1
<if test="title!=null">
and title = #{title}
if>
<if test="author!=null">
and author = #{author}
if>
select>
where where标签当底下的条件都不成立不会被执行,当第一个有and或or会自动去掉
<select id="queryBlogwhere" parameterType="map" resultType="blog">
select * from blog
<where>
<if test="title!=null">
and title = #{title}
if>
<if test="author!=null">
and author = #{author}
if>
where>
select>
choose 有时候我们不想用到所有的条件语句,而只是想选其中的一项,有点像switch
包含when标签,当XXX(条件)执行(语句)
当when都不成立,执行otherwise里的语句
<select id="queryBlogchoose" parameterType="map" resultType="blog">
select * from blog
<where>
<when test="title!=null">
and title = #{title}when>
<when test="author!=null">
and author = #{author}when>
<otherwise>
and views=#{views}otherwise>
where>
select>
set 类似于 解决动态更新的操作,会自动删除无关的逗号
<update id="updatedata" paramterType="map">
update blog
<set>
<if test="title!=null">
title = #{title},
if>
<if test="author!=null">
author = #{author}set>
where id=#{id}
update>
trim 用于去掉指定前缀后缀(一般不用)
<trim prefix="Where" prefixOverrides="AND|OR">
....
trim>
<trim prefix="SET" suffixOverrides=",">
<if test="title=null&author!=null">
title,if>
trim>
sql片段
用于提高代码复用
<sql id="if-title-author">
<if test="title!=null">
and title = #{title}
if>
<if test="author!=null">
and author = #{author}
if>
sql>
<select id="queryBlogwhere" parameterType="map" resultType="blog">
select * from blog
<where>
<include refid="if-title-author">include>
where>
select>
foreach
如查询集合内id的信息
List findList(ArrayList list);
List findList01( List list);
用于遍历
<select>select * from User where in
<foreach item="id" collection="Array" open="[" separator="," close="]">
#{id}
foreach>select>
<select id="findList01" resultType="com.demo1.pojo.DemoUser" parameterType="java.util.List">
select * from demo_user where id in <foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
foreach>
select>
查询连接数据库非常消耗资源
一次查询的结果我们可以将其暂存在一个可直接取到的地方-----内存:缓存
我们再次查询相同的数据,直接走缓存
Mybatis缓存
mybatis系统默认定义了两级缓存:一级缓存和二级缓存
一级缓存
默认开启,同一个SqlSesion级别共享的缓存,在一个SqlSession的生命周期内,执行2次相同的SQL查询,则第二次SQL查询会直接取缓存的数据,而不走数据库,当然,若第一次和第二次相同的SQL查询之间,执行了DML(INSERT/UPDATE/DELETE),则一级缓存会被清空,第二次查询相同SQL仍然会走数据库
一级缓存在下面情况会被清除
flushCache=true
,这样会导致该MappedStatement的一级缓存,二级缓存都失效(一个CRUD标签在mybatis中会被封装成一个MappedStatement)
,这样会使一级缓存失效,二级缓存不受影响测试一级缓存:打开日志
缓存失效:
二级缓存(也叫全局缓存)
默认关闭,可通过全局配置文件中的开启二级缓存总开关,然后在某个具体的mapper.xml中增加
工作机制:
一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
新的会话查询信息,就可以从二级缓存中获取内容;
不同的mapper查出的数据会放在自己对应的缓存(map)中;
步骤:
<setting name="cacheEnabled" value="true"/>
<cache/>
也可以对其进行配置具体见说明文档帮助文档
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
<select id="updateUser" parameterType="int" useCache="true">
select * from user where id = #{id}
select>
Ehcache是一种广泛使用的java分布式缓存,用于通用缓存(现在流行用redis)
使用步骤:
1. 要在应用程序中使用Ehcache,需要引入依赖的jar包
<dependency>
<groupId>org.mybatis.cachesgroupId>
<artifactId>mybatis-ehcacheartifactId>
<version>1.1.0version>
dependency>
2. 在mapper使用对应的缓存
<mapper namespace = “org.acme.FooMapper” >
<cache type = “org.mybatis.caches.ehcache.EhcacheCache” />
mapper>
ehcache.xml
文件,如果在加载时未找到/ehcache.xml
资源或出现问题,则将使用默认配置。
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<diskStore path="./tmpdir/Tmp_EhCache"/>
<defaultCache
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="259200"
memoryStoreEvictionPolicy="LRU"/>
<cache
name="cloud_user"
eternal="false"
maxElementsInMemory="5000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
memoryStoreEvictionPolicy="LRU"/>
ehcache>