4, Cache and annotation development of mybatis

Posted by j0hn_ on Wed, 10 Jun 2020 09:32:03 +0200

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 {

 

 

 

 

Topics: Mybatis xml Session Java