Mybatis
Mybatis
持久化
数据持久化
- 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
- 内存:断电即失
- 数据库(jdbc),io文件持久化.
持久层
- 完成持久化工作的代码块
- 界限十分明显。
第一个mybatis程序
- 导入依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
- 编写mybatis工具类
package com.fiee.utlis;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
//sqlSessionFactory sqlsession
public class MybatisUtlis {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//使用mybatis第一步获取sqlSessionFactory对象
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了sqlSessionFactory,顾名思义,我们就可以获得sqlsession的实例了
//sqlsession完全包含了面向数据库执行sql命令所需的所有方法
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
编写代码
-
实体类
package com.fiee.pojo; //实体类 public class Account { private int id; private String name; private double money; public Account() { } public Account(int id, String name, double money) { this.id = id; this.name = name; this.money = money; } 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 double getMoney() { return money; } public void setMoney(double money) { this.money = money; } @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}'; } }
-
Dao类
-
package com.fiee.dao; import com.fiee.pojo.Account; import java.util.List; public interface AccountDao { List<Account> getAccountList(); }
-
接口实现类,由原来接口实现类转变为一个Mapper.xml文件
<?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.fiee.dao.AccountDao">
<!-- id对应原来的方法名字 resultType 是接口约为实现接口类-->
<select id="getAccountList" resultType="com.fiee.pojo.Account">
select * from account
</select>
</mapper>
测试
package com.fiee;
import com.fiee.dao.AccountDao;
import com.fiee.pojo.Account;
import com.fiee.utlis.MybatisUtlis;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class TestDao {
@Test
public void test(){
//获得sqlsession对象
SqlSession sqlSession = MybatisUtlis.getSqlSession();
//执行SQL
AccountDao mapper = sqlSession.getMapper(AccountDao.class);
List<Account> accountList = mapper.getAccountList();
for (Account account:accountList) {
System.out.println(account);
}
//关闭sqlsession
sqlSession.close();
}
}
Map
传递Map中的key
Map传递参数,直接在sql中取出key即可[parameterType="map"]
对象传递参数,直接在sql中取对象的属性即可!
只有一个基本类型参数的情况下,可以直接在sql中取到!
多个参数用Map,或者注解
配置解析
1.核心配置文件
-
mybatis-config.xml
-
MyBatis的配置文件包含了会深深影响MyBatis行为的设置和属性信息
configuration<configuration><!-- 配置 --> <properties /><!-- 属性 --> <settings /><!-- 设置 --> <typeAliases /><!-- 类型命名 --> <typeHandlers /><!-- 类型处理器 --> <objectFactory /><!-- 对象工厂 --> <plugins /><!-- 插件 --> <environments><!-- 配置环境 --> <environment><!-- 环境变量 --> <transactionManager /><!-- 事务管理器 --> <dataSource /><!-- 数据源 --> </environment> </environments> <databaseIdProvider /><!-- 数据库厂商标识 --> <mappers /><!-- 映射器 --> </configuration>
配置环境(environments)
Mybatis可以配置成适应多种环境
不过要记住:尽管可以配置多个环境,但每个sqlsessionFactory实例只能选择一种环境
学会适应配置多套运行环境
Mybatis默认的事务管理器就是JDBC,连接池:POOLED
属性(properties)
我们可以通过properties属性来实现引用配置文件
这些属性都是可外部配置且动态替换的,既可以在典型的java属性文件中配置,亦可以通过properties元素的子元素来传递(db.properties)
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/accountinfo?useSSl=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456
在核心配置文件中映入
<properties resource="db.properties">
<property name="" value=""/>
</properties>
- 可以直接引入外部文件
- 可以在其中增加一些属性配置
- 如果两个文件有同一个字段,优先使用外部配置文件的
类型别名(typeAliases)
- 类型别名可为 Java 类型设置一个缩写名字。
- 意在降低冗余的全限定类名书写
<!-- 可以给实体类取别名-->
<typeAliases>
<typeAlias type="com.fiee.pojo.Account" alias="Account"/>
</typeAliases>
-
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,
- 扫描实体类的包,它的默认别名就为这个类的首字母小写的类名
-
在实体类上使用注解命名@Alias("")
-
<typeAliases> <package name="com.fiee.pojo"/> </typeAliases>
在实体类比较少的时候使用第一种
实体类十分多,使用第二种
第一种可以diy别名,第二种不行(但可以在注解取@Alias(""))
设置
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 |
true | false | false |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
映射器(mappers)
MapperRegistry:注册绑定我们的Mapper文件;
方式一:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>
方式二:
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
注意点:
- 接口和他的Mapper配置文件必须同名
- 接口和他的Mapper配置文件必须在同一个包下!
方式三:
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
注意点:
- 接口和他的Mapper配置文件必须同名
- 接口和他的Mapper配置文件必须在同一个包下!
生命周期和作用域
作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder
- 一旦创建了 SqlSessionFactory,就不再需要它了。
- 局部变量
SqlSessionFactory
- 说白了就是可以想象为:数据库连接词
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
- 因此 SqlSessionFactory 的最佳作用域是应用作用域。
- 最简单的就是使用单例模式或者静态单例模式。
SqlSession
- 连接到连接池的一个请求!
- 用完关闭,否则资源被占用!
解决属性名和字段名不一致的问题
resultMap
结果集映射
<!-- 结果集映射-->
<resultMap id="AccountMap" type="Account">
<!-- coulumn数据库中的字段,property实体类中的属性-->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="money" property="money"/>
</resultMap>
<select id="getAccountList" resultMap="AccountMap">//这个跟上面id一样
select * from account
</select>
-
resultMap元素是Mybatis中最强大的元素
-
ResultMap的设计是想是,对于简单的语句根本不需要配置显示的结果集映射,而复杂一点的语句只需要描述他们的关系就行了
-
ResultMap
的优秀之处——你完全可以不用显式地配置它们 -
需要映射谁就写谁就好了
日志
日志工厂
如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手!
曾经:sout,debug
现在:日志工厂
logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 未设置
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
Log4j
什么是Log4j
- 可以通过控制日志信息输送的目的地是控制台,文件,GUI组件
- 我们也可以控制每一条日志的输出格式
- 通过定义每一条日志信息的级别,我们能够更加细致的控制日志的生成过程
- 通过一个配置文件来灵活地配置,而不需要修改应用代码
1.先导入log4j的包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
后面要用百度配置
简单使用
-
在要使用log4j的类中,导入包import org.apache.log4j.Logger
-
在日志对象,参数为当前类的class
static Logger logger=Logger.getLogger(UserDaoTest.class)
-
日志级别
logger.info("info:进入了testLog4j"); logger.debug("debug:进入了testLog4j"); logger.error("error:进入了testLog4j");
分页
- 减少数据的处理量
使用mybatis实现分页,核心SQL
- 接口
- Mapper.xml
- 测试
注解开发
-
注解在接口上实现
-
@select("select * from user") List<User> getUsers();
-
需要在核心配置文件中绑定接口!
-
<绑定接口> <mappers> <mapper class="com.xx.xx.xx"/> </mappers>
-
测试
Lombok
使用步骤:
- 在idea中安装Lombok插件
- 在项目中导入lombok的jar包(maven)
- 在实体类上加上注解即可(data)
多对一
使用结果集映射
复杂的属性,我们需要单独处理
对象:association
集合:collection
<resultMap id="AccountMap" type="Account">
<!-- coulumn数据库中的字段,property实体类中的属性-->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="money" property="money"/>
<collection property="money" column="s" javaType="传入表的类型" select="嵌套查询,联合的表id"
</resultMap>
<select id="getAccountList" resultMap="AccountMap">
select * from account
</select>
注:
javaType指定属性的类型
集合中的泛型信息,我们使用ofType获取
动态SQL
什么是动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句
if -where标签
接口方法 查询员工 根据不同的条件来判断
/**
* 动态sql if where 标签 根据传入参数不同动态判断条件
*/
Employee selectDByEmp(Employee employee);
<select id="selectDByEmp" resultType="com.yu.pojo.Employee">
select id,last_name,email,salary
from tbl_employee
<where>
<if test="id != null">
and id=#{id}
</if>
<if test="lastName != null ">
and last_name=#{lastName}
</if>
<if test="email != null">
and email=#{email}
</if>
<if test="salary != null">
and salary=#{salary}
</if>
</where>
</select>
choose标签
/**
* 动态sql choose 标签 单条件查询 有一个条件满足就只接受一个条件 即使有多个条件满足 也无法加入进来
* 相当于 if-else 或者 switch-case
*/
Employee selectDByChoose(Employee employee);
<select id="selectDByChoose" resultType="com.yu.pojo.Employee">
select id,last_name,email,salary
from tbl_employee
<where>
<choose>
<when test="id != null">
id=#{id}
</when>
<when test="lastName != null">
last_name=#{lastName}
</when>
<when test="email != null and">
email=#{email}
</when>
<when test="salary != null and">
salary=#{salary}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</where>
</select>
set标签
set标签 解决语句上的逗号问题 注意写在where前面
</insert>
<update id="update">
update tbl_employee
<set>
<if test="lastName != null ">
last_name=#{lastName},
</if>
<if test="email != null ">
email=#{email},
</if>
<if test="salary != null ">
salary=#{salary},
</if>
</set>
where
id=#{id}
</update>
Sql片段
有时候,我们可能会将一些功能的部分抽取出来,方便复用!
- 使用SQL标签抽取公共部分
- 在需要使用的地方使用include标签引用即可
注意事项:
- 最好基于单表来定义SQL片段!
- 不要存where标签
- 尽量只存if判断就可以了
<select id= "queryAllUser" resultType= "User">
select <include refid= "userColumn"></include> from tb_ user
</ select>
Foreach
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
//collection指定的集合, open是开头是什么 separator是拼接符 close是最后
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
二级缓存
步骤:
-
开启缓存
-
<settings> <setting name="cacheEnabled" value="true"/> </setting>
-
在当前Mapper.xml中使用二级缓存
-
<cache/>
小结:
- 只要开启了二级缓存,在同一个Mapper下就有效
- 所有的数据都会先放在一级缓存中
- 只有当会话提交,或者关闭的时候,才会提交到二级缓存中