Mybatis高级

一、延迟加载
延迟加载(懒加载):需要关联信息时再去按需加载关联信息,能大大提高数据库性能
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 的。

一级缓存原理(默认开启):
Mybatis高级_第1张图片
测试代码:

    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语句)
Mybatis高级_第2张图片
如果中间执行了sqlSession.commit();,同样的查询SQL输出两次
Mybatis高级_第3张图片
二级缓存原理:
Mybatis高级_第4张图片
因为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();测试结果为:
Mybatis高级_第5张图片
第一次缓存中没有记录,命中率为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包
Mybatis高级_第6张图片
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&amp;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的声明式事务
避免脏数据和错误的数据提交到数据库,一般读取缓存里的数据,容易产生脏数据
事务的四大原则:一致性 隔离性 持久性 原子性

你可能感兴趣的:(JAVA框架)