Mybatis 緩存三

MyBatis緩存分爲一級緩存和二級緩存html

一級緩存java

MyBatis的一級緩存指的是在一個Session域內,session爲關閉的時候執行的查詢會根據SQL爲key被緩存(跟mysql緩存同樣,修改任何參數的值都會致使緩存失效)mysql

1)單獨使用MyBatis而不繼承Spring,使用原生的MyBatis的SqlSessionFactory來構造sqlSession查詢,是可使用以及緩存的,示例代碼以下web

複製代碼
public class Test {
    public static void main(String[] args) throws IOException {
        String config = "mybatis-config.xml";
        InputStream is = Resources.getResourceAsStream(config);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        SqlSession session = factory.openSession();
        System.out.println(session.selectOne("selectUserByID", 1));
        // 同一個session的相同sql查詢,將會使用一級緩存 
        System.out.println(session.selectOne("selectUserByID", 1));
        // 參數改變,須要從新查詢
        System.out.println(session.selectOne("selectUserByID", 2));
        // 清空緩存後須要從新查詢
        session.clearCache();
        System.out.println(session.selectOne("selectUserByID", 1));
        // session close之後,仍然使用同一個db connection
        session.close();
        session = factory.openSession();
        System.out.println(session.selectOne("selectUserByID", 1));
    }
}
複製代碼

輸出以下spring

DEBUG - Openning JDBC Connection
DEBUG - Created connection 10044878.
DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ? 
DEBUG - ==> Parameters: 1(Integer)
1|test1|19|beijing
1|test1|19|beijing
DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ? 
DEBUG - ==> Parameters: 2(Integer)
2|test2|18|guangzhou
DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ? 
DEBUG - ==> Parameters: 1(Integer)
1|test1|19|beijing
DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - Returned connection 10044878 to pool.
DEBUG - Openning JDBC Connection
DEBUG - Checked out connection 10044878 from pool.
DEBUG - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ? 
DEBUG - ==> Parameters: 1(Integer)
1|test1|19|beijingsql

看以看出來,當參數不變的時候只進行了一次查詢,參數變動之後,則須要從新進行查詢,而清空緩存之後,參數相同的查詢過的SQL也須要從新查詢,並且使用的數據庫鏈接是同一個數據庫鏈接,這裏要得益於咱們在mybatis-config.xml裏面的datasource設置數據庫

複製代碼
<environments default="development">
        <environment id="development">
            <transactionManager type="JDBC">

            </transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>
複製代碼

注意datasource使用的是POOLED,也就是使用了鏈接池,因此數據庫鏈接可回收利用,固然這個environment屬性在集成spring的時候是不須要的,由於咱們須要另外配置datasource的bean.apache

 

2) 跟Spring集成的時候(使用mybatis-spring)緩存

直接在dao裏查詢兩次一樣參數的sqlsession

複製代碼
@Repository
public class UserDao extends SqlSessionDaoSupport {
    public User selectUserById(int id) {
        SqlSession session = getSqlSession();
        session.selectOne("dao.userdao.selectUserByID", id);
        // 因爲session的實現是SqlSessionTemplate的動態代理實現
        // 它已經在代理類內執行了session.close(),因此無需手動關閉session
        return session.selectOne("dao.userdao.selectUserByID", id);
    }
}
複製代碼

觀察日誌

DEBUG - Creating a new SqlSession
DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e389b8] was not registered for synchronization because synchronization is not active
DEBUG - Fetching JDBC Connection from DataSource
DEBUG - JDBC Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
DEBUG - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
DEBUG - ==> Parameters: 1(Integer)
DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e389b8]
DEBUG - Returning JDBC Connection to DataSource
DEBUG - Creating a new SqlSession
DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@169da74] was not registered for synchronization because synchronization is not active
DEBUG - Fetching JDBC Connection from DataSource
DEBUG - JDBC Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
DEBUG - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
DEBUG - ==> Parameters: 1(Integer)
DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@169da74]
DEBUG - Returning JDBC Connection to DataSource

 

這裏執行了2次sql查詢,看似咱們使用了同一個sqlSession,可是實際上由於咱們的dao繼承了SqlSessionDaoSupport,而SqlSessionDaoSupport內部sqlSession的實現是使用用動態代理實現的,這個動態代理sqlSessionProxy使用一個模板方法封裝了select()等操做,每一次select()查詢都會自動先執行openSession(),執行完close()之後調用close()方法,至關於生成了一個新的session實例,因此咱們無需手動的去關閉這個session()(關於這一點見下面mybatis的官方文檔),固然也沒法使用mybatis的一級緩存,也就是說mybatis的一級緩存在spring中是沒有做用的.

官方文檔摘要

MyBatis SqlSession provides you with specific methods to handle transactions programmatically. But when using MyBatis-Spring your beans will be injected with a Spring managed SqlSession or a Spring managed mapper. That means that Spring will always handle your transactions.

You cannot call SqlSession.commit()SqlSession.rollback() or SqlSession.close() over a Spring managed SqlSession. If you try to do so, a UnsupportedOperationException exception will be thrown. Note these methods are not exposed in injected mapper classes.

 

二級緩存

二級緩存就是global caching,它超出session範圍以外,能夠被全部sqlSession共享,它的實現機制和mysql的緩存同樣,開啓它只須要在mybatis的配置文件開啓settings裏的

<setting name="cacheEnabled" value="true"/>

以及在相應的Mapper文件(例如userMapper.xml)裏開啓

複製代碼
<mapper namespace="dao.userdao">
   ...  select statement ...
       <!-- Cache 配置 -->
    <cache
        eviction="FIFO"
        flushInterval="60000"
        size="512"
        readOnly="true" />
</mapper>
複製代碼

須要注意的是global caching的做用域是針對Mapper的Namespace而言的,也就是說只在有在這個Namespace內的查詢才能共享這個cache.例如上面的 dao.userdao namespace, 下面是官方文檔的介紹

It's important to remember that a cache configuration and the cache instance are bound to the namespace of the SQL Map file. Thus, all statements in the same namespace as the cache are bound by it.

例以下面的示例,咱們執行兩次對同一個sql語句的查詢,觀察輸出日誌

    @RequestMapping("/getUser")
    public String getUser(Model model) {
        User user = userDao.selectUserById(1);
        model.addAttribute(user);
        return "index";
    }

當咱們訪問兩次 /getUser 這個url,查看日誌輸出

DEBUG - Creating a new SqlSession
DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@659812] was not registered for synchronization because synchronization is not active
DEBUG - Cache Hit Ratio [dao.userdao]: 0.0
DEBUG - Fetching JDBC Connection from DataSource
DEBUG - JDBC Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
DEBUG - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ? 
DEBUG - ==> Parameters: 1(Integer)
DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@659812]
DEBUG - Returning JDBC Connection to DataSource
DEBUG - Invoking afterPropertiesSet() on bean with name 'index'
DEBUG - Rendering view [org.springframework.web.servlet.view.JstlView: name 'index'; URL [/index.jsp]] in DispatcherServlet with name 'dispatcher'
DEBUG - Added model object 'org.springframework.validation.BindingResult.user' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'index'
DEBUG - Added model object 'user' of type [bean.User] to request in view with name 'index'
DEBUG - Forwarding to resource [/index.jsp] in InternalResourceView 'index'
DEBUG - Successfully completed request
DEBUG - Returning cached instance of singleton bean 'sqlSessionFactory'
DEBUG - DispatcherServlet with name 'dispatcher' processing GET request for [/user/getUser]
DEBUG - Looking up handler method for path /user/getUser
DEBUG - Returning handler method [public java.lang.String controller.UserController.getUser(org.springframework.ui.Model)]
DEBUG - Returning cached instance of singleton bean 'userController'
DEBUG - Last-Modified value for [/user/getUser] is: -1
DEBUG - Creating a new SqlSession
DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@539a92] was not registered for synchronization because synchronization is not active
DEBUG - Cache Hit Ratio [dao.userdao]: 0.5
DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@539a92]
DEBUG - Rendering view [org.springframework.web.servlet.view.JstlView: name 'index'; URL [/index.jsp]] in DispatcherServlet with name 'dispatcher'
DEBUG - Added model object 'org.springframework.validation.BindingResult.user' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'index'
DEBUG - Added model object 'user' of type [bean.User] to request in view with name 'index'
DEBUG - Forwarding to resource [/index.jsp] in InternalResourceView 'index'
DEBUG - Successfully completed request

能夠看出第二次訪問同一個url的時候相同的查詢 hit cache了,這就是global cache的做用

相關文章
相關標籤/搜索