一、延迟加载
延迟加载(懒加载):需要关联信息时再去按需加载关联信息,能大大提高数据库性能
Mybatis默认是不开启延迟加载功能的,我们需要手动开启!
首先配置xml文件(我这里命名的是mybatis-config.xml)
设置项 | 描述 |
---|---|
lazyLoadingEnabled | 默认值为false,关闭延迟加载 |
aggressiveLazyLoading | 默认值为true,开启积极加载 |
关键代码如下:
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 关闭积极加载-->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 当你调用toString方法无效时加载-->
<setting name="lazyLoadTriggerMethods" value=""/>
二、缓存
mybatis提供查询缓存,如果缓存中有数据就不用从数据库中获取,用于减轻数据压力,提高系统性能。
一级缓存是 SqlSession 级别的缓存。在操作数据库时需要构造 sqlSession 对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的 sqlSession 之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是 mapper 级别的缓存,多个 SqlSession 去操作同一个 Mapper 的 sql 语句,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
String path = "mybatis-config.xml";
try {
InputStream in = Resources.getResourceAsStream(path);
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = ssf.openSession();
RoleMapper roleMapper= sqlSession.getMapper(RoleMapper.class);
System.out.println(roleMapper.selectByRoleId(3));
// sqlSession.commit();
System.out.println("-------------分割线--------------");
RoleMapper roleMapper1= sqlSession.getMapper(RoleMapper.class);
System.out.println(roleMapper1.selectByRoleId(3));
} catch (IOException e) {
e.printStackTrace();
}
测试结果:(同样的查询,只输出一次SQL语句)
如果中间执行了sqlSession.commit();,同样的查询SQL输出两次
二级缓存原理:
因为mybatis默认是没有开启二级缓存,所以需要开启二级缓存,同样是在核心xml文件里配置(我这里是mybatis-config.xml)
具体代码:
<!--开机二级缓存总开关-->
<setting name="cacheEnabled" value="true" />
然后在相应的映射文件中加入cache标签并且相应的实体类要实现序列化,如下:
<mapper namespace="com.offcn.dao.RoleMapper">
<cache />
public class Role implements Serializable {...
测试时要关闭一级缓存,也就是要执行sqlSession.commit();测试结果为:
第一次缓存中没有记录,命中率为0.0;
第二次缓存中有记录,则命中率0.5(访问两次,有一次命中)
清空缓存可调用sqlSession.clearCache(),也可在相应的映射文件中配置,代码如下:
<!--useCache 代表禁用二级缓存 默认为true flushCache="true" 代表刷新(清空)二级缓存,默认为false-->
<select id="selectById" parameterType="int" resultMap="selectByIdResulet" useCache="false" flushCache="true">
select * from smbms_user where id=#{id}
</select>
三、Spring 与 mybatis的整合
1.导入jar包
2.配置核心xml文件(applicationContext.xml)
①配置数据库,加载数据库,加载其他xml文件:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<!--配置数据库-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<!-- <property name="url">
<value><![CDATA[jdbc:mysql://127.0.0.1:3306/smbms?
useUnicode=true&characterEncoding=utf-8]]></value>
</property> -->
<property name="url" value="jdbc:mysql://127.0.0.1:3306/smbms?
useUnicode=true&characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--引入数据库资源-->
<property name="dataSource" ref="dataSource"></property>
<!--加载mybatis核心配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
②引入dao层,有两种方式
第一种:
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.offcn.mapper.UserMapper"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
第二种:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.offcn.mapper"></property>
</bean>
③引入service层
<bean id="userService" class="com.offcn.service.impl.UserServiceImpl">
<property name="userMapper" ref="userMapper"></property>
</bean>
④定义一个事务管理器
<!--定义一个事物管理器-->
<bean id="transactionManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--引入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
⑤定义事务通知(两种)
第一种:
<!--定义事物通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManger">
<tx:attributes>
<!--name代表对应的方法名 第二个代表是事物的传播行为,事物失效的时间,事物的隔离级别--> <!--指定异常进行回滚-->
<tx:method name="find" propagation="SUPPORTS" timeout="-1" isolation="DEFAULT" />
<tx:method name="add" propagation="REQUIRED"></tx:method>
<tx:method name="*" propagation="REQUIRED"></tx:method>
</tx:attributes>
</tx:advice>
<!--定义切面-->
<aop:config>
<aop:pointcut id="serviceMethod" expression="execution(* com.offcn.service.UserService.*(..))"></aop:pointcut>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"></aop:advisor>
</aop:config>
第二种(注解的方式,需要在ServiceImpl里配置注解):
<!--自动扫描包-->
<context:component-scan base-package="com.offcn.service"/>
<!--开启注解驱动-->
<tx:annotation-driven/>
@Service("userService")
//事务的注解
@Transactional
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addUser(List<User> userList){
for (User user:userList) {
int i = userMapper.addUser(user);
if( i>0 ){
System.out.println("添加成功");
}
}
}
}
总结:Spring的声明式事务
避免脏数据和错误的数据提交到数据库,一般读取缓存里的数据,容易产生脏数据
事务的四大原则:一致性 隔离性 持久性 原子性