キャッシュとは、データが保存されるメモリ内の領域です。目的は、クエリ効率を向上させることです。 MyBatis はクエリ結果をキャッシュに保存し、次回が同じ SQL を実行するとき、データベースにアクセスせず、結果をキャッシュから直接取得するため、サーバーへの負荷が軽減されます。
#キャッシュとは何ですか?MyBatis 一次キャッシュはローカル キャッシュとも呼ばれます。 SqlSession オブジェクトには Executor オブジェクトが含まれており、Executor オブジェクトには 1 次キャッシュ データを格納する PerpetualCache オブジェクトが含まれています。メモリ内に存在するデータの一部。
キャッシュの役割とは何ですか?プログラムとデータベース間の対話を減らし、クエリの効率を向上させ、サーバーとデータベースの負荷を軽減します。
どのような種類のデータがキャッシュされますか?頻繁にクエリされるが、頻繁には変更されず、変更後の結果にほとんど影響を与えないデータ。
MyBatis キャッシュのカテゴリは何ですか?レベル 1 キャッシュとレベル 2 キャッシュ
2 つの SQL が同じかどうかを判断するにはどうすればよいですか?クエリの SQL ステートメントは同じ、渡されるパラメータ値は同じ、結果セットの要件は同じ、プリコンパイルされたテンプレート ID は同じです
2 . Mabtis 一次キャッシュ
# (1) 1 次キャッシュをテストします 実際、テスト方法は非常に簡単で、同じおよび異なる SqlSession オブジェクトを使用して SQL クエリを実行することで、返されたオブジェクトのハッシュ値が同じかどうかを知ることができます。返される値は同じです。これは、SQL クエリが実行されないことを意味しますが、キャッシュからオブジェクトを直接取得して返します。一次キャッシュは SqlSession オブジェクト内にあるため、同じ SqlSession オブジェクトを使用してデータベースを操作する場合にのみ、一次キャッシュを共有できます。
MyBatis の 1 次キャッシュはデフォルトで有効になっており、構成は必要ありません。
#以下に示すように:
以下は、同じ Session オブジェクトを使用してクエリを実行します。 user1 と user2 のハッシュ値が同じ場合、一次キャッシュが実際に有効になっていることを意味し、クエリはありませんが、データはキャッシュから直接取得されます。
import com.mybatisstudy.mapper.UserMapper; import com.mybatisstudy.pojo.User; 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 org.junit.Test; import java.io.InputStream; public class TestUserMapper3 { // 测试使用同一个SqlSession查询 @Test public void testCache1() throws Exception{ InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session = factory.openSession(); // 使用同一个SqlSession查询 UserMapper mapper1 = session.getMapper(UserMapper.class); UserMapper mapper2 = session.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1.hashCode()); System.out.println("------------------------------------------"); User user2 = mapper2.findById(1); System.out.println(user2.hashCode()); session.close(); } }
実行結果
## OK、実際に返されたハッシュ値は同じです。コンソール出力を通じて、クエリではなくキャッシュからオブジェクトを直接取得して返すことを示すことができるため、これは 1 次キャッシュであり、クエリの効率が向上します。
テスト用のさまざまな SQL セッションで、返されたハッシュ値が一貫しているかどうか
// 测试使用不同SqlSession查询 @Test public void testCache2() throws Exception{ InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session1 = factory.openSession(); SqlSession session2 = factory.openSession(); // 测试使用不同SqlSession查询 UserMapper mapper1 = session1.getMapper(UserMapper.class); UserMapper mapper2 = session2.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1.hashCode()); System.out.println("---------------------------------"); User user2 = mapper2.findById(1); System.out.println(user2.hashCode()); session1.close(); session2.close(); }ログイン後にコピー
OK、返されたハッシュ値が異なることがわかります。また、コンソールの出力表示からも、これがクエリであることがわかります。一次キャッシュは確かに SqlSession オブジェクトに基づいています
(2) 一次キャッシュをクリアしますただし、キャッシュが多すぎるとクエリの効率にも影響するため、一次キャッシュをクリアする必要があります。携帯電話のキャッシュを時々クリアしないと非常にスタックしてしまうのと同じ理由で、一次キャッシュをクリアするにはどうすればよいでしょうか?
SqlSession は close() を呼び出します。SqlSession オブジェクトは、操作が停止され、オブジェクトのキャッシュされたデータも利用できなくなります。
SqlSession は、clearCache() / commit() を呼び出します。この操作により、1 次キャッシュ データがクリアされます。
- SqlSession は、追加、削除、変更メソッドを呼び出します。この操作により、1 次キャッシュ データがクリアされます。追加、削除、変更後にデータベースが変更されるため、キャッシュされたデータは不正確になります。
// 清空Mybatis一级缓存 @Test public void testCache3() throws Exception{ InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session = factory.openSession(); UserMapper mapper1 = session.getMapper(UserMapper.class); UserMapper mapper2 = session.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1.hashCode()); // 清空Mybatis一级缓存 session.clearCache(); System.out.println("-------------------------------"); User user2 = mapper2.findById(1); System.out.println(user2.hashCode()); session.close(); }ログイン後にコピー実行効果
OK、返されたハッシュ値は確かに異なる SqlSession オブジェクトを使用して上記のクエリを実行する場合、コンソール入力の表示は少し異なります。つまり、ここで JDBC 接続を確立する必要がなく、クエリの効率も効果的に向上します。それでも時々キャッシュをクリアする必要があります
MyBatis二级缓存也叫全局缓存。数据存放在SqlSessionFactory中,只要是同一个工厂对象创建的SqlSession,在进行查询时都能共享数据。一般在项目中只有一个SqlSessionFactory对象,所以二级缓存的数据是全项目共享的。
MyBatis一级缓存存放的是对象,二级缓存存放的是对象的数据。所以要求二级缓存存放的POJO必须是可序列化的,也就是要实现Serializable接口。
MyBatis二级缓存默认不开启,手动开启后数据先存放在一级缓存中,只有一级缓存数据清空后,数据才会存到二级缓存中。
SqlSession 调用 clearCache() 无法将数据存到二级缓存中。
1. POJO类实现Serializable接口
import java.io.Serializable; public class User implements Serializable { private int id; private String username; private String sex; private String address; }
2. 在Mybatis配置文件添加如下设置
ログイン後にコピー
这里有个额外知识,就是Mybatis配置文件的标签还得按照顺序来放的,否则就会以下编译错误;
The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,
objectWrapperFactory?,reflectorFactory?,plugins?,environments?,
databaseIdProvider?,mappers?)".
同时也说明了放置顺序就得按照match里面的顺序来放
3. 添加
如果查询到的集合中对象过多,二级缓存只能缓存1024个对象引用。可以通过
标签的size属性修改该数量。 比如:
那怎么测试呢,从上面我们可以知道二级缓存存放的是对象的数据,并且是基于SqlSessionFactory的,因此我们可以用SqlSessionFactory获取两个SqlSession对象,然后让他们分别获取各自的mapper,然后进行查询,返回到同一个实例化的USer对象中,如果返回的数据是一致的,但是对象的哈希值是不一样的话,则说明二级缓存里存放的确实对象的数据而不是对象。
// 测试二级缓存 @Test public void testCache4() throws Exception { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session = factory.openSession(); UserMapper mapper1 = session.getMapper(UserMapper.class); UserMapper mapper2 = session.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1); System.out.println(user1.hashCode()); // 让一级缓存失效 session.commit(); System.out.println("----------------------------"); user1 = mapper2.findById(1); System.out.println(user1); System.out.println(user1.hashCode()); }
运行结果
OK,从运行结果上我们可以知道结果集返回到同一个对象中,而他们的哈希值反而不一样,说明执行第二次查询的时候新建了一个对象并且该对象指向那个对象并且将SqlSessionFactory中的数据赋值到新建的那个对象。其实从控制台打印的日志我们也可以得出,并没有执行查询方法,因为没有打印SQL语句,而且缓存也是从0.0改成了0.5,因此我们可以断定二级缓存存放的是数据而不是对象。
以上がJava Mybatis の 1 次キャッシュと 2 次キャッシュとは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。