1, Loading time in mybatis
Question: in one to many, when we have a user, it has 100 accounts.
When querying users, do you want to find out the associated accounts?
Do you want to find out the associated users when querying accounts?
When querying users, the account information under users should be, when to use and when to query.
When querying an account, the user information of the account should be queried together with the account query.
What is delayed loading
Only when the data is actually used can the query be initiated and not when it is not used. Load on demand (lazy load)
What is immediate load
No matter whether it is used or not, as soon as the method is called, the query is initiated immediately.
Among the four corresponding table relationships: one to many, many to one, one to one, many to many
One to many, many to many: usually we use delay loading.
Many to one, one to one: usually we use immediate loading.
1. Enable delay loading
SqlMapConfig.xml Configuration in: enable delay loading
<!--configuration parameter--> <settings> <!--open Mybatis Supports delayed loading--> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"></setting> </settings>
2. One to one delayed loading
IAccountDao.xml
<!-- Define encapsulation account and user Of resultMap --> <resultMap id="accountUserMap" type="account"> <id property="id" column="id"></id> <result property="uid" column="uid"></result> <result property="money" column="money"></result> <!-- One to one relationship mapping: configuration encapsulation user Content of select Property: query the unique identity of the user: column Property: user specified by id The value of the required parameter when querying --> <association property="user" column="uid" javaType="user" select="com.weilai.dao.IUserDao.findById"></association> </resultMap> <!-- Query all --> <select id="findAll" resultMap="accountUserMap"> select * from account </select> <!-- According to users id Query account list --> <select id="findAccountByUid" resultType="account"> select * from account where uid = #{uid} </select>
3. Many to one delayed loading
IUserDao.xml
<!-- definition User Of resultMap--> <resultMap id="userAccountMap" type="user"> <id property="id" column="id"></id> <result property="username" column="username"></result> <result property="address" column="address"></result> <result property="sex" column="sex"></result> <result property="birthday" column="birthday"></result> <!-- to configure user In object accounts Mapping of sets --> <collection property="accounts" ofType="account" select="com.weilai.dao.IAccountDao.findAccountByUid" column="id"></collection> </resultMap> <!-- Query all --> <select id="findAll" resultMap="userAccountMap"> select * from user </select> <!-- according to id Query users --> <select id="findById" parameterType="INT" resultType="user"> select * from user where id = #{uid} </select>
2, Primary and secondary caching in mybatis
1. Basic concept of cache
What is cache
Temporary data that exists in memory.
Why cache
Reduce the number of interactions with the database and improve the efficiency of execution.
What kind of data can be cached and what kind of data can not be used
For caching:
Frequently queried and not frequently changed.
The correctness of the data has little effect on the final result.
Not for cache:
Constantly changing data
The correctness of the data has a great influence on the final result.
For example: the inventory of goods, the exchange rate of banks, and the stock market price.
2. First level cache in mybatis
First level cache:
It refers to the cache of SqlSession object in Mybatis.
When we execute the query, the results of the query will be stored in the area provided by SqlSession.
The structure of the area is a Map. When we query the same data again, mybatis will go to SQL session first
Check if there is any, and use it directly if there is any.
When the SqlSession object disappears, the first level cache of mybatis disappears.
The first level cache is the cache of SqlSession scope. When calling the modify, add, delete, commit(), close() and other methods of SqlSession, the first level cache will be cleared.
UserTest.java Test the synchronization of L1 cache and cache
public class UserTest { private InputStream in; private SqlSessionFactory factory; private SqlSession sqlSession; private IUserDao userDao; @Before//For execution before test method execution public void init()throws Exception{ //1. Read configuration file and generate byte input stream in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2. Get SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in); //3. Get SqlSession object sqlSession = factory.openSession(true); //4. Get the proxy object of dao userDao = sqlSession.getMapper(IUserDao.class); } @After//For execution after test method execution public void destroy()throws Exception{ //Commit transaction // sqlSession.commit(); //6. Release resources sqlSession.close(); in.close(); } /** * Test L1 cache */ @Test public void testFirstLevelCache(){ User user1 = userDao.findById(41); System.out.println(user1); // sqlSession.close(); //Get SqlSession object again // sqlSession = factory.openSession(); sqlSession.clearCache();//This method can also clear the cache userDao = sqlSession.getMapper(IUserDao.class); User user2 = userDao.findById(41); System.out.println(user2); System.out.println(user1 == user2); } /** * Test cache synchronization */ @Test public void testClearlCache(){ //1. Query users by id User user1 = userDao.findById(41); System.out.println(user1); //2. Update user information user1.setUsername("update user clear cache"); user1.setAddress("Haidian District, Beijing"); userDao.updateUser(user1); //3. Query the user with id 41 again, and it will not be obtained from the session User user2 = userDao.findById(41); System.out.println(user2); System.out.println(user1 == user2); } }
3. Secondary cache in mybatis
L2 cache
It refers to the cache of SqlSessionFactory objects in Mybatis. SqlSession created by the same SqlSessionFactory object shares its cache. The second level cache stores data, not objects, so the objects obtained from the second level cache twice are not the same object
Steps to use L2 cache:
Step 1: let the Mybatis framework support L2 caching (in SqlMapConfig.xml Configuration in)
<settings> <setting name="cacheEnabled" value="true"/> </settings>
Step 2: make the current mapping file support level 2 caching (in IUserDao.xml Configuration in)
<?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"> <mapper namespace="com.weilai.dao.IUserDao"> <!--open user Supports L2 caching--> <cache/>
Step 3: enable the current operation to support the secondary cache (configured in the select tab)
<!-- according to id Query users --> <select id="findById" parameterType="INT" resultType="user" useCache="true"> select * from user where id = #{uid} </select>
Test L2 cache
public class SecondLevelCacheTest { private InputStream in; private SqlSessionFactory factory; @Before//For execution before test method execution public void init()throws Exception{ //1. Read configuration file and generate byte input stream in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2. Get SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in); } @After//For execution after test method execution public void destroy()throws Exception{ in.close(); } /** * Test L2 cache */ @Test public void testFirstLevelCache(){ SqlSession sqlSession1 = factory.openSession(); IUserDao dao1 = sqlSession1.getMapper(IUserDao.class); User user1 = dao1.findById(41); System.out.println(user1); sqlSession1.close();//First level cache disappears SqlSession sqlSession2 = factory.openSession(); IUserDao dao2 = sqlSession2.getMapper(IUserDao.class); User user2 = dao2.findById(41); System.out.println(user2); sqlSession2.close(); System.out.println(user1 == user2); } }
3, Annotation development of mybatis
1. Environment construction
pom.xml
<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> </dependencies>
SqlMapConfig.xml
<?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> <!-- Import external profile--> <properties resource="jdbcConfig.properties"></properties> <!--Configure alias--> <typeAliases> <package name="com.weilai.domain"></package> </typeAliases> <!-- Configure environment--> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </dataSource> </environment> </environments> <!-- Specify annotated dao Interface location --> <mappers> <mapper class="com.weilai.dao.IUserDao"></mapper> </mappers> </configuration>
2. Single table CRUD operation (proxy Dao mode)
IUserDao.java
public interface IUserDao { /** * Query all users * @return */ @Select("select * from user") List<User> findAll(); /** * Save user * @param user */ @Insert("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})") void saveUser(User user); /** * Update users * @param user */ @Update("update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}") void updateUser(User user); /** * delete user * @param userId */ @Delete("delete from user where id=#{id} ") void deleteUser(Integer userId); /** * Query users by id * @param userId * @return */ @Select("select * from user where id=#{id} ") User findById(Integer userId); /** * Fuzzy query based on user name * @param username * @return */ // @Select("select * from user where username like #{username} ") @Select("select * from user where username like '%${value}%' ") List<User> findUserByName(String username); /** * Total number of users queried * @return */ @Select("select count(*) from user ") int findTotalUser(); }
AnnotationCRUDTest.java
public class AnnotationCRUDTest { private InputStream in; private SqlSessionFactory factory; private SqlSession session; private IUserDao userDao; @Before public void init()throws Exception{ in = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(in); session = factory.openSession(); userDao = session.getMapper(IUserDao.class); } @After public void destroy()throws Exception{ session.commit(); session.close(); in.close(); } @Test public void testSave(){ User user = new User(); user.setUsername("mybatis annotation"); user.setAddress("Changping District, Beijing"); userDao.saveUser(user); } @Test public void testUpdate(){ User user = new User(); user.setId(57); user.setUsername("mybatis annotation update"); user.setAddress("Haidian District, Beijing"); user.setSex("male"); user.setBirthday(new Date()); userDao.updateUser(user); } @Test public void testDelete(){ userDao.deleteUser(51); } @Test public void testFindOne(){ User user = userDao.findById(57); System.out.println(user); } @Test public void testFindByName(){ // List<User> users = userDao.findUserByName("%mybatis%"); List<User> users = userDao.findUserByName("mybatis"); for(User user : users){ System.out.println(user); } } @Test public void testFindTotal(){ int total = userDao.findTotalUser(); System.out.println(total); } }
3. Annotation establishes correspondence between entity attribute and database table column name
IUserDao.java
public interface IUserDao { /** * Query all users * @return */ @Select("select * from user") @Results(id="userMap",value={ @Result(id=true,column = "id",property = "userId"), @Result(column = "username",property = "userName"), @Result(column = "address",property = "userAddress"), @Result(column = "sex",property = "userSex"), @Result(column = "birthday",property = "userBirthday") }) List<User> findAll(); /** * Query users by id * @param userId * @return */ @Select("select * from user where id=#{id} ") @ResultMap("userMap") User findById(Integer userId);
4. Multi table query
One to many: IUserDao.java
public interface IUserDao { /** * Query all users * @return */ @Select("select * from user") @Results(id="userMap",value={ @Result(id=true,column = "id",property = "userId"), @Result(column = "username",property = "userName"), @Result(column = "address",property = "userAddress"), @Result(column = "sex",property = "userSex"), @Result(column = "birthday",property = "userBirthday"), @Result(property = "accounts",column = "id", many = @Many(select = "com.weilai.dao.IAccountDao.findAccountByUid", fetchType = FetchType.LAZY)) }) List<User> findAll(); /** * Query users by id * @param userId * @return */ @Select("select * from user where id=#{id} ") @ResultMap("userMap") User findById(Integer userId);
Many to one is also one to one: IAccountDao.java
public interface IAccountDao { /** * Query all accounts and obtain the user information of each account * @return */ @Select("select * from account") @Results(id="accountMap",value = { @Result(id=true,column = "id",property = "id"), @Result(column = "uid",property = "uid"), @Result(column = "money",property = "money"), @Result(property = "user",column = "uid",one=@One(select="com.weilai.dao.IUserDao.findById",fetchType= FetchType.EAGER)) }) List<Account> findAll(); /** * Query account information according to user id * @param userId * @return */ @Select("select * from account where uid = #{userId}") List<Account> findAccountByUid(Integer userId); }
5. Cache configuration
1. Enable the secondary cache in the main configuration file, which is enabled by default
SqlMapConfig.xml
<!--Configure enable L2 cache--> <settings> <setting name="cacheEnabled" value="true"/> </settings>
2. Add a comment to Dao class
@CacheNamespace(blocking = true) public interface IUserDao {