一、概述
是数据访问层框架,底层是对 JDBC 的封装。使用 mybatis 时不需要编写实现类,只需要写需要执行的 sql 命令,同时解决了jdbc效率低,sql在程序中拼接、sql参数赋值、ResultSet遍历不利于维护的问题。
1.1 框架中主要的类
运行时相关的类
ResourcesMyBatis 中 IO 流的工具类 加载配置文件 SqlSessionFactoryBuilder() 构建器 创建 SqlSessionFactory 接口的实现类 XMLConfigBuilder MyBatis 全局配置文件内容构建器类 作用负责读取流内容并转换为 JAVA 代码 Configuration 封装了全局配置文件所有配置信息. 全局配置文件内容存放在 Configuration 中 DefaultSqlSessionFactory SqlSessionFactory接口的实现类 Transaction 事务类 SqlSession 会带有一个 Transaction 对象. TransactionFactory 事务工厂 负责生产 Transaction Executor MyBatis 执行器 负责执行 SQL 命令,默认的执行器 SimpleExcutor
批量操作 BatchExcutor 通过 openSession(参数控制)DefaultSqlSession SqlSession 接口的实现类 ExceptionFactoryMyBatis 异常工厂
1.2 执行流程描述
在 MyBatis 运行开始时需要先通过 Resources 加载全局配置文件.下面 需要实例化 SqlSessionFactoryBuilder 构建器.帮助 SqlSessionFactory 接 口实现类 DefaultSqlSessionFactory. 在实例化 DefaultSqlSessionFactory 之前需要先创建 XmlConfigBuilder 解析全局配置文件流,并把解析结果存放在 Configuration 中.之后把 Configuratin 传递给 DefaultSqlSessionFactory.到此 SqlSessionFactory 工 厂创建成功. 由 SqlSessionFactory 工厂创建 SqlSession. 每次创建 SqlSession 时,都需要由 TransactionFactory 创建 Transaction 对象,同时还需要创建 SqlSession 的执行器 Excutor,最后实例化 DefaultSqlSession,传递给 SqlSession 接口. 根据项目需求使用 SqlSession 接口中的 API 完成具体的事务操作. 如果事务执行失败,需要进行 rollback 回滚事务. 如果事务执行成功提交给数据库.关闭 SqlSession
1.3 缓存
一级缓存
一级缓存区域是根据SqlSession为单位划分的。
每次查询会先从缓存区域找,如果找不到从数据库查询,查询到数据将数据写入缓存。
Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象
sqlSession执行insert、update、delete等操作commit提交后会清空缓存区域。
二级缓存
二级缓存区域是根据mapper的namespace划分的,相同namespace的mapper查询数据放在同一个区域,如果使用mapper代理方法每个mapper的namespace都不同,此时可以理解为二级缓存区域是根据mapper划分。
每次查询会先从缓存区域找,如果找不到从数据库查询,查询到数据将数据写入缓存。
Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象
sqlSession执行insert、update、delete等操作commit提交后会清空缓存区域。
注意:二级缓存需要查询结果映射的pojo对象实现java.io.Serializable接口实现序列化和反序列化操作,注意如果存在父类、成员pojo都需要实现序列化接口。
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
1.4 注意事项
#{} 和 ${} 的区别
#{} SQL 使用?占位符 、获取参数的内容可以使用 0(索引)、param1、arg0获取第一个参数。
如果只有一个参数(基本数据类型或 String),mybatis 对#{}里面内容没有要求只要写内容即可. 如果时对象,则可以直接使用属性名。如果是map,则可以直接使用key
**${}**字符串拼接不使用?,默认找 ${内容}内容的 get/set 方法,如 果写数字,就是一个数字
Mapper特殊字符转译
如果在 xml 文件中出现 “<” , “>” ,双引号 等特殊字符时可以使用 XML 文件转义标签(XML自身的)
<![CDATA[ 内容 ]]>
事务
在 mybatis 中默认是关闭了 JDBC 的自动提交功能 ,每一个 SqlSession 默认都是不自动提交事务. 提交事务需要通过session.commit()提交事务.或者通过openSession(true);自动提交.setAutoCommit(true); 开启自动提交。
在 openSession()时 Mybatis 会创建 SqlSession 时同时创建一个 Transaction(事务对象),同时 autoCommit 都为 false ,如果出现异常,应该 session.rollback()回滚事务
增删改返回值
mybatis 底层是对 JDBC 的封装. 所以,mybatis 中<insert> <delete> <update>标签没有 resultType 属性, 认为返回值都是 int
Mysql驱动问题
MySQL驱动升级到8以后要求强制配置时区,如果不设置会出问题。
解决方式:
- 在url上拼接配置。serverTimezone=Asia/Shanghai
- 修改mysql中的配置文件mysql.ini,在mysqld项中添加default-time-zone=+8:00
二、使用示例
2.1 与spring集成
依赖
<!--MyBatis依赖包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!--MySQL驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>runtime</scope>
</dependency>配置
<?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">
<!—创建一个配置文件,将连接数据库的信息存入,简化修改信息的操作 resource是配置文件的路径+名称-->
<properties resource="配置文件的路径及名称"></properties>
<!-- 配置环境参数 -->
<settings>
<!-- 开启日志输出 -->
<setting name="logImpl" value="STDOUT_LOGGING"></setting>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 关闭侵入性延迟加载 侵入性延迟加载代表,如果访问了主数据对象,关联数据自动加载。 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!-- 类型别名 -->
<typeAliases>
<!-- 对type值的类创建一个别名alias值,直接写alias的值即可调用type -->
<!-- <typeAlias type=类名全路径" alias="类的别名"></typeAlias> -->
<!-- 批量定义别名 对name包下的类起别名 别名就是类名 大小写不区分-->
<package name="包的路径"></package>
</typeAliases>
<configuration>
<!-- default 引用 environment 的 id,当前所使用的环境 -->
<environments default="default">
<!--
1.1 <transactionManager/> type 属性可取值
1.1.1 JDBC,事务管理使用 JDBC 原生事务管理方式
1.1.2 MANAGED 把事务管理转交给其他容器.原生 JDBC 事务 setAutoMapping(false);
1.2 <dataSouce/>type 属性
1.2.1 POOLED 使用数据库连接池
1.2.2 UNPOOLED 不实用数据库连接池,和直接使用 JDBC 一样
1.2.3 JNDI :java 命名目录接口技术. -->
<!-- 声明可以使用的环境 -->
<environment id="default">
<!-- 使用原生 JDBC 事务 -->
<transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!-- 使用properties时配置连接属性的方式 name和value对应配置文件中的值-->
<propertyname="driver" value="${键名}"></property>
<property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
<property name="username" value="root"/>
<property name="password" value="smallming"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/bjsxt/mapper/FlowerMapper.xml"/>
</mappers>
</configuration>mapper文件
<?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">
<!-- namesapce:理解成实现类的全路径(包名+类名) -->
<mapper namespace="a.b" >
<mapper namespace="com.mapper.UserMapper">
<!-- 开启当前mapper的二级缓存 -->
<cache></cache>
</mapper>
<!-- id:方法名 parameterType:定义参数类型 resultType:返回值类型. 如果方法返回值是 list,在 resultType 中写 List 的泛型, 因为 mybatis 对 jdbc 封装,一行一行读取数据 -->
<select id="selAll"
resultType="com.bjsxt.pojo.Flower">
select * from flower
</select>
</mapper>代码
InputStream is = Resources.getResourceAsStream("myabtis.xml");
//使用工厂设计模式
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//生产
SqlSession SqlSession session=factory.openSession();
List<Flower> list = session.selectList("a.b.selAll");
for (Flower flower : list) {
System.out.println(flower.toString());
}
session.close();
// 查询集合
List<Flower> list = session.selectList("a.b.selAll");
for (Flower flower : list) {
System.out.println(flower.toString());
}
// 查询单个对象
int count = session.selectOne("a.b.selById"); System.out.println(count);
// 查询map对象
Map<Object, Object> map = session.selectMap("a.b.c", "name123");
System.out.println(map);2.2 springboot整合
依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.5</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>配置
spring:
datasource:
name: mydb
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1:3306/sb_db
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
mapper-locations: classpath*:/mybatis/*Mapper.xml扫描包路径
@MapperScan("包名")配置类
/**
* Mybatis支持*匹配扫描包
*
* @author ruoyi
*/
@Configuration
public class MyBatisConfig {
@Autowired
private Environment env;
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
public static String setTypeAliasesPackage(String typeAliasesPackage) {
ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
List<String> allResult = new ArrayList<String>();
try {
for (String aliasesPackage : typeAliasesPackage.split(",")) {
List<String> result = new ArrayList<String>();
aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
Resource[] resources = resolver.getResources(aliasesPackage);
if (resources != null && resources.length > 0) {
MetadataReader metadataReader = null;
for (Resource resource : resources) {
if (resource.isReadable()) {
metadataReader = metadataReaderFactory.getMetadataReader(resource);
try {
result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
if (result.size() > 0) {
HashSet<String> hashResult = new HashSet<String>(result);
allResult.addAll(hashResult);
}
}
if (allResult.size() > 0) {
typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
} else {
throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
}
} catch (IOException e) {
e.printStackTrace();
}
return typeAliasesPackage;
}
public Resource[] resolveMapperLocations(String[] mapperLocations) {
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
List<Resource> resources = new ArrayList<Resource>();
if (mapperLocations != null) {
for (String mapperLocation : mapperLocations) {
try {
Resource[] mappers = resourceResolver.getResources(mapperLocation);
resources.addAll(Arrays.asList(mappers));
} catch (IOException e) {
// ignore
}
}
}
return resources.toArray(new Resource[resources.size()]);
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
String mapperLocations = env.getProperty("mybatis.mapperLocations");
String configLocation = env.getProperty("mybatis.configLocation");
typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
VFS.addImplClass(SpringBootVFS.class);
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
return sessionFactory.getObject();
}
}三、基础知识
3.1 接口绑定
// 示例接口
public interface LogMapper {
List<Log> selAll();
/**
* mybatis 把参数转换为 map 了,其中@Param("key") 参数内 容就是 map 的 value * @param accin123
* @param accout3454235
* @return
*/
List<Log> selByAccInAccout(@Param("accin") String accin123,@Param("accout") String accout3454235);
}
// 示例mapper
//namespace 必须和接口全限定路径(包名+类名)一致
//id 值必须和接口中方法名相同
//如果接口中方法为多个参数,可以省略 parameterType
<mapper namespace="com.bjsxt.mapper.LogMapper">
<!-- 当多参数时,不需要写 parameterType -->
<!-- 当Mapper类方法中没有使用@Param时时,#{}中使用 0,1,2 或 param1,param2 -->
<select id="selByAccInAccout" resultType="log" >
select * from log where accin=#{accin} and accout=#{accout}
</select>
</mapper>3.2 动态sql
Mapper中逻辑判断
<!-- if判断 -->
<!-- OGNL 表达式,直接写 key 或对象的属性.不需要添加任 何特字符号 -->
<if test="accin!=null and accin!=''">
and accin=#{accin}
</if>
<!-- where拼接 -->
<!--
当编写 where 标签时,如果内容中第一个是 and 去掉第一个 and
如果<where>中有内容会生成 where 关键字,如果没有内容不 生成 where 关键
-->
<where>
<if test="accin!=null and accin!=''">
and accin=#{accin}
</if>
</where>
<!-- chose多判断 -->
<choose>
<when test="accin!=null and accin!=''">
and accin=#{accin}
</when>
<when test="accout!=null and accout!=''">
and accout=#{accout}
</when>
</choose>
<!-- set赋值 -->
<!--
去掉最后一个逗号
如果<set>里面有内容生成 set 关键字,没有就不生成
-->
<set>
id=#{id},
<if test="accIn!=null and accIn!=''">
accin=#{accIn},
</if>
<if test="accOut!=null and accOut!=''">
accout=#{accOut},
</if>
</set>
<!-- trim -->
<!--
prefix 在前面添加内容
prefixOverrides 去掉前面内容
suffix 在后面添加内容
suffixOverrieds 去掉后面内容
执行顺序去掉内容后添加内容
-->
<trim prefix="set" suffixOverrides=",">
a=a,
</trim>
<!-- bind -->
<!-- 给参数重新赋值 在原内容前或后添加内容 -->
<bind name="accin" value="'%'+accin+'%'"/>
<!-- foreach -->
<!--
collectino=”” 要遍历的集合
item 迭代变量, #{迭代变量名}获取内容
open 循环后左侧添加的内容
close 循环后右侧添加的内容
separator 每次循环时,元素之间的分隔符
-->
<foreach collection="list" item="abc" open="(" close=")" separator=",">
#{abc}
</foreach>
<!-- sql -->
<!-- sql片段复用 -->
<sql id="mysql">
id,accin,accout,money
</sql>
<!-- include -->
<!-- 引用sql片段 -->
<include refid="mysql"></include>
<!-- resultMap -->
<!-- 控制SQL查询结果与 实体类的映射关系 默认 MyBatis 使用 Auto Mapping 特性 -->
<resultMap type="teacher" id="mymap">
<!-- 主键使用 id 标签配置映射关系 -->
<id column="id" property="id1" />
<!-- 其他列使用 result 标签配置映射关系 -->
<result column="name" property="name1"/>
</resultMap>
<!-- 使用<resultMap>标签时,<select>标签不写 resultType 属性,而是使 用 resultMap 属性引用<resultMap>标签
useCache 禁用二级缓存
-->
<select id="selAll" resultMap="mymap" useCache="false">
select * from teacher
</select>
<!-- resultMap中关联单个对象 -->
<resultMap type="student" id="stuMap">
<result column="tid" property="tid"/>
<!--
<association>装配一个对象时使用
property: 对象在类中的属性名
select:通过哪个查询查询出这个对象的信息
column: 把当前表的哪个列的值做为参数传递给另 一个查询
大前提使用 N+1 方式.时如果列名和属性名相同可以不配置,使用 Auto mapping 特性.但是 mybatis 默认只会给列专配一次
-->
<association property="teacher" select="com.bjsxt.mapper.TeacherMapper.selById" column="tid"></association>
<!--
column 对应sql查询的名称
property对应实体类中属性名。
-->
<association property="teacher"javaType="Teacher" >
<id column="tid" property="id"/>
<result column="tname" property="name"/>
</association>
<collection property="list" select="com.bjsxt.mapper.StudentMapper.selByTid" column="id"></collection>
<collection property="list" ofType="student" >
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="age" property="age"/>
<result column="tid" property="tid"/>
</collection>
</resultMap>
<!-- Auto Mapping 结合别名实现多表查询 -->
<!-- 对应字段名可通过实体类的属性名.属性名方式赋值,.在 SQL 是关键字符,两侧添加反单引号 -->
<select id="selAll" resultType="student">
select t.id `teacher.id`,t.name `teacher.name`,s.id id,s.name name,age,tid from student s LEFT JOIN teacher t on t.id=s.tid
</select>
<!-- 插入数据获取插入的id
* useGeneratedKeys:是够获取自动增长的主键值。true表示获取
* keyProperty :指定将获取到的主键值封装到哪儿个属性里
* flushCache 刷新缓存
-->
<insert id="add" useGeneratedKeys="true" keyProperty="id" flushCache="true">
<!-- <selectKey resultType="java.lang.String" order="BEFORE" keyProperty="id">
select uuid()
</selectKey> -->
</insert>3.3 注解使用
//注解可以简化 mapper.xml 文件. 但如果涉及动态 SQL 依然使用 mapper.xml 。mapper.xml 和注解可以共存.
@Select("select * from teacher")
@Insert("insert into teacher values(default,#{name})")
@Update("update teacher set name=#{name} where id=#{id}")
@Delete("delete from teacher where id=#{0}")
@Results() //相当于<resultMap>
@Result() //相当于<id/>或<result/>
@Result(id=true) //相当与<id/>
@Many() //相当于<collection/>
@One() //相当于<association/>
@Results(value={
@Result(id=true,property="id",column="id"),
@Result(property="name",column="name"),
@Result(property="list",column="id",many
=@Many(select="com.bjsxt.mapper.StudentMapper.selByTid")//一对多
)
@Result(property = "user", column = "uid", javaType = User.class,
one = @One(select = "com.itheima.dao.UserDao.findById", fetchType = FetchType.LAZY))// 一对一
})
@Select("select * from teacher")3.4 缓存使用
缓存可以使应用程序减少对数据库的访问交互这个耗时的过程,提升程序运行效率
缓存流程
- 先去缓存区中找是否存在 statement
- 如果有返回结果 如果没有缓存 statement 对象,去数据库获取数据
- 数据库返回查询结果
- 把查询结果放到对应的缓存区中
缓存开启
<!-- sqlSession缓存 -->
<!-- 默认开启,作用域是同一个sqlSession对象 -->
<!-- 二级缓存 -->
<!--
有效范围:同一个 factory 内哪个 SqlSession 都可以获取
当数据频繁被使用,很少被修改时候使用二级缓存
-->
<settings>
<!-- 开启二级缓存的支持 -->
<!--cacheEnabled的取值默认就为true。为true代表开启二级缓存;为false代表不开启二级缓存。-->
<setting name="cacheEnabled" value="true"/></settings>
@CacheNamespace(blocking=true)<!-- mybatis基于注解方式实现配置二级缓存 -->
<!-- 使用二级缓存 -->
<!--
在 mapper.xml 中添加
如果不写 readOnly=”true”需要把实体类序列化
-->
<cache readOnly="true"></cache>
<!-- 当 SqlSession 对象 close()时或 commit()时会把 SqlSession 缓存 的数据刷(flush)到 SqlSessionFactory 缓存区中 -->3.5 分页插件
原理:通过拦截Executor 执行器的执行语句,在其后拼接分页信息。
依赖
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.6</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper‐spring‐boot‐starter</artifactId>
<version>1.2.4</version>
</dependency>配置说明
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注意其他配置 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<!--使用下面的方式配置参数,一行配置一个 -->
<value>
params=value1
</value>
</property>
</bean>
</array>
</property>
</bean>参数介绍:同下配置的property中的name和value
- helperDialect :分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect 属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:oracle , mysql , mariadb , sqlite , hsqldb , postgresql , db2 , sqlserver , informix , h2 , sqlserver2012 , derby 特别注意:使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012 ,否则会使用 SqlServer2005 的方式进行分页。你也可以实现 AbstractHelperDialect ,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。
- offsetAsPageNum :默认值为 false ,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为true 时,会将 RowBounds 中的 offset 参数当成 pageNum 使用,可以用页码和页面大小两个参数进行分页。
- rowBoundsWithCount :默认值为false ,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为true 时,使用 RowBounds 分页会进行 count 查询。
- pageSizeZero :默认值为 false ,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit =0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。
- reasonable :分页合理化参数,默认值为false 。当该参数设置为 true 时, pageNum<=0 时会查询第一页, pageNum>pages (超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
- params :为了支持startPage(Object params) 方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable ,不配置映射的用默认值, 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。
- supportMethodsArguments :支持通过 Mapper 接口参数来传递分页参数,默认值false ,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTest 和ArgumentsObjTest 。
- autoRuntimeDialect :默认值为 false 。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择sqlserver2012 ,只能使用sqlserver )。
- closeConn :默认值为 true 。当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认true 关闭,设置为false 后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。
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>
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 告诉分页插件是哪个数据库 -->
<property name="dialect" value="mysql"/> </plugin>
</plugins>
</configuration>spring配置
<!-- SqlSessionFactory -->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.ego.pojo"></property>
<property name="configLocation" value="classpath:mybatis.xml"></property>
</bean>代码实现
List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(1, 10));
//这种情况下也会进行物理分页查询
List<Country> selectAll(RowBounds rowBounds);
//由于默认情况下的 RowBounds 无法获取查询总数,分页插件提供了一个继承自 RowBounds 的PageRowBounds ,这个对象中增加了 total 属性,执行分页查询后,可以从该属性得到查询总数。
PageHelper.startPage(page, rows);
//查询全部
List<TbItem> list = tbItemMapper.selectByExample(new TbItemExample());
//分页代码
//设置分页条件
PageInfo<TbItem> pi = new PageInfo<>(list);3.6 整合ehcache缓存
通过实现Cache接口可以实现mybatis缓存数据通过其它缓存数据库整合,mybatis的特长是sql操作,缓存数据的管理不是mybatis的特长,为了提高缓存的性能将mybatis和第三方的缓存数据库整合,比如ehcache、memcache、redis等。
依赖
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.0.2</version>
</dependency>ehcache配置文件
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="F:\develop\ehcache" />
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>属性说明:
- diskStore:指定数据在磁盘中的存储位置。
- defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用
<defalutCache/>指定的的管理策略
以下属性是必须的:
- maxElementsInMemory - 在内存中缓存的element的最大数目
- maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
- eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
- overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
以下属性是可选的:
- timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
- timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
- diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
- diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
- diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
- memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
开启缓存
修改mapper.xml
<cache type="org.mybatis.caches.ehcache.EhcacheCache" >
<property name="timeToIdleSeconds" value="3600"/>
<property name="timeToLiveSeconds" value="3600"/>
<!-- 同ehcache参数maxElementsInMemory -->
<property name="maxEntriesLocalHeap" value="1000"/>
<!-- 同ehcache参数maxElementsOnDisk -->
<property name="maxEntriesLocalDisk" value="10000000"/>
<property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>四、附录
4.1 mybatis相关文档
【MyBatis】自定义MyBatis的实现_骑着蜗牛ひ追导弹'的博客-CSDN博客
4.2 mybatis-settings配置
| Setting(设置) | Description(描述) | Valid Values(验证值组) | Default(默认值) |
|---|---|---|---|
| cacheEnabled | 在全局范围内启用或禁用缓存配置任何映射器在此配置下。 | true | false | TRUE |
| lazyLoadingEnabled | 在全局范围内启用或禁用延迟加载。禁用时,所有协会将热加载。 | true | false | TRUE |
| aggressiveLazyLoading | 启用时,有延迟加载属性的对象将被完全加载后调用懒惰的任何属性。否则,每一个属性是按需加载。 | true | false | TRUE |
| multipleResultSetsEnabled | 允许或不允许从一个单独的语句(需要兼容的驱动程序)要返回多个结果集。 | true | false | TRUE |
| useColumnLabel | 使用列标签,而不是列名。在这方面,不同的驱动有不同的行为。参考驱动文档或测试两种方法来决定你的驱动程序的行为如何。 | true | false | TRUE |
| useGeneratedKeys | 允许JDBC支持生成的密钥。兼容的驱动程序是必需的。此设置强制生成的键被使用,如果设置为true,一些驱动会不兼容性,但仍然可以工作。 | true | false | FALSE |
| autoMappingBehavior | 指定MyBatis的应如何自动映射列到字段/属性。NONE自动映射。 PARTIAL只会自动映射结果没有嵌套结果映射定义里面。 FULL会自动映射的结果映射任何复杂的(包含嵌套或其他)。 | NONE, PARTIAL, FULL | PARTIAL |
| defaultExecutorType | 配置默认执行人。SIMPLE执行人确实没有什么特别的。 REUSE执行器重用准备好的语句。 BATCH执行器重用语句和批处理更新。 | SIMPLE REUSE BATCH | SIMPLE |
| defaultStatementTimeout | 设置驱动程序等待一个数据库响应的秒数。 | Any positive integer | Not Set (null) |
| safeRowBoundsEnabled | 允许使用嵌套的语句RowBounds。 | true | false | FALSE |
| mapUnderscoreToCamelCase | 从经典的数据库列名A_COLUMN启用自动映射到骆驼标识的经典的Java属性名aColumn。 | true | false | FALSE |
| localCacheScope | MyBatis的使用本地缓存,以防止循环引用,并加快反复嵌套查询。默认情况下(SESSION)会话期间执行的所有查询缓存。如果localCacheScope=STATMENT本地会话将被用于语句的执行,只是没有将数据共享之间的两个不同的调用相同的SqlSession。 | SESSION | STATEMENT | SESSION |
| dbcTypeForNull | 指定为空值时,没有特定的JDBC类型的参数的JDBC类型。有些驱动需要指定列的JDBC类型,但其他像NULL,VARCHAR或OTHER的工作与通用值。 | JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER | OTHER |
| lazyLoadTriggerMethods | 指定触发延迟加载的对象的方法。 | A method name list separated by commas | equals,clone,hashCode,toString |
| defaultScriptingLanguage | 指定所使用的语言默认为动态SQL生成。 | A type alias or fully qualified class name. | org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver |
| callSettersOnNulls | 指定如果setter方法或地图的put方法时,将调用检索到的值是null。它是有用的,当你依靠Map.keySet()或null初始化。注意原语(如整型,布尔等)不会被设置为null。 | true | false | FALSE |
| logPrefix | 指定的前缀字串,MyBatis将会增加记录器的名称。 | Any String | Not set |
| logImpl | 指定MyBatis的日志实现使用。如果此设置是不存在的记录的实施将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | Not set |
| proxyFactory | 指定代理工具,MyBatis将会使用创建懒加载能力的对象。 | CGLIB | JAVASSIST |
4.3 mybatis默认支持别名
| 别名 | 映射的类型 |
|---|---|
| _byte | byte |
| _long | long |
| _short | short |
| _int | int |
| _integer | int |
| _double | double |
| _float | float |
| _boolean | boolean |
| string | String |
| byte | Byte |
| long | Long |
| short | Short |
| int | Integer |
| integer | Integer |
| double | Double |
| float | Float |
| boolean | Boolean |
| date | Date |
| decimal | BigDecimal |
| bigdecimal | BigDecimal |