MyBatis -- annotation, cache configuration, other tools

1, Annotation

I've been familiar with the basic use of MyBatis. For some simple sql statements, such as adding, deleting, modifying and querying a table, you can use the annotations provided by MyBatis to save the steps of writing mapping files and complex multi table queries. It is recommended to use mapping files

1. Select notes

Using the Select annotation, the database query operation can be realized

Query the department according to the department number

Entity class:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept implements Serializable {
    /**
     * Department number
     */
    private Integer deptno;
    /**
     * Department name
     */
    private String dname;
    /**
     * address
     */
    private String loc;
}
copy

Define interface method:

public interface DeptMapper {
    /**
     * Query department by department number
     * @param deptno
     * @return
     */
    @Select("select * from dept where deptno = #{deptno}")
    Dept findDeptByDeptno(int deptno);
}
copy

The method of using parameters in SQL statements is the same as that in #{} the mapping file. You can also use annotations to specify the name of parameters

public interface DeptMapper {
    /**
     * Query Department No
     * @param deptno
     * @return
     */
    @Select("select * from dept where deptno = #{no}")
    Dept findDeptByDeptno(@Param("no") int deptno);
}
copy

Test method:

    //Query department by department number
    @Test
    public void test1() {
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = mapper.findDeptByDeptno(10);
        System.out.println(dept);
    }
copy
2. Insert notes

Add a new department information

Define interface method:

    /**
     * Add a new department information
     *
     * @param dept
     * @return
     */
    @Insert("insert into dept values(#{deptno},#{dname},#{loc})")
    int addDept(Dept dept);
copy

sql parameters use attribute names

Test method:

    //Add a new department information
    @Test
    public void test2() {
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = new Dept(50,"ALGORITHM","Paris");
        int rows = mapper.addDept(dept);
        System.out.println(rows);

        sqlSession.commit();
    }
copy
3. Update notes

Update department information according to department number

Define interface method:

    /**
     * Update department information according to department number
     * @param dept
     * @return
     */
    @Update("update dept set dname = #{dname}, loc = #{loc} where deptno = #{deptno}")
    int updateDept(Dept dept);
copy

Test method:

    //Update department information according to department number
    @Test
    public void test3() {
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = new Dept(50,"ALGORITHM","Tokyo");
        int rows = mapper.updateDept(dept);
        System.out.println(rows);

        sqlSession.commit();
    }
copy
4. Delete annotation

Delete department according to department number

Define interface method:

    /**
     * Delete department according to department number
     * @param deptno
     * @return
     */
    @Delete("delete from dept where deptno = #{deptno}")
    int deleteDeptbyDeptno(int deptno);
copy

Test method:

    //Delete department according to department number
    @Test
    public void test4() {
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        int rows = mapper.deleteDeptbyDeptno(50);
        System.out.println(rows);

        sqlSession.commit();
    }
copy

2, Cache configuration

MyBatis has its own L1 cache and L2 cache, and also supports third-party cache, such as redis and ehcache

1. L1 cache

The L1 cache is enabled by default and exists in each SqlSession object. For the same query, if it exists in the L1 cache, it will not go to the database and return directly

For test1 method, obtain two mappers through sqlSession and perform the same operation. Finally, check whether the query result is the same object:

    //Query department by department number
    @Test
    public void test1() {
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = mapper.findDeptByDeptno(10);
        System.out.println(dept);
        DeptMapper mapper2 = sqlSession.getMapper(DeptMapper.class);
        Dept dept2 = mapper2.findDeptByDeptno(10);
        System.out.println(dept2);

        System.out.println(dept == dept2);
    }
copy

result:

2. L2 cache

The L2 cache can span sqlsessions. The condition is that it is created by the same SqlSessionFactory. The L2 cache is closed by default. The following steps are required to open it

  • 2.1 global switch

It is configured in the MyBatis core configuration file and supports L2 cache

    <settings>
...
        <!--Enable L2 cache-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
copy
  • 2.2 enable L2 cache in mapper
  • Opening method in java: Use CacheNamespace annotation on interface
@CacheNamespace
public interface DeptMapper {
copy
  • Opening method in mapping file: Use the cache tag and set useCache="true" for queries that need to be cached
<mapper namespace="com.aruba.mapper.DeptMapper">
    <cache/>

<!--    Dept findDeptByDeptno(@Param("no") int deptno);-->
    <select id="findDeptByDeptno" resultType="dept" useCache="true">
        select * from dept where deptno = #{no}
    </select>
</mapper>
copy

In addition, the entity class needs to implement the serialization interface because it may be stored on disk

  • 2.3 commit or close operation of sqlsession

SqlSession will first look in the L2 cache. If it does not exist, query the database and put the data into the L2 cache when commit() or close()

Test method:

public class Test1 {
    private SqlSession sqlSession;
    private SqlSession sqlSession2;

    @Before
    public void init() throws IOException {
        SqlSessionFactoryBuilder sb = new SqlSessionFactoryBuilder();
        // Pass in the configuration file as a parameter
        SqlSessionFactory sqlSessionFactory = sb.build(Resources.getResourceAsStream("sqlMapConfig.xml"));
        sqlSession = sqlSessionFactory.openSession();
        sqlSession2 = sqlSessionFactory.openSession();
    }

    //Query department by department number - L2 cache
    @Test
    public void test5() {
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = mapper.findDeptByDeptno(10);
        System.out.println(dept);
        sqlSession.commit();

        DeptMapper mapper2 = sqlSession2.getMapper(DeptMapper.class);
        Dept dept2 = mapper2.findDeptByDeptno(10);
        System.out.println(dept2);
    }

    @After
    public void release() {
        if (sqlSession != null)
            sqlSession.close();
        
        if (sqlSession2 != null)
            sqlSession2.close();
    }
}
copy

result:

Only one sql was executed

3. Third party cache

When it comes to distributed systems, the cache provided by MyBatis cannot meet the requirements. Ehcache is used as the third-party cache below

Import dependency:

        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.0.2</version>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.10.1</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.2</version>
        </dependency>
copy

Create the configuration file ehcache. Exe in the resources directory xml:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd"
         updateCheck="true" monitoring="autodetect"
         dynamicConfig="true">

    <diskStore path="D:\aruba\ehcache" />
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>

</ehcache>
copy

L2 cache configuration:

  • In Java: CacheNamespace annotation, specifying the Class using the cache
@CacheNamespace(implementation = EhcacheCache.class)
public interface DeptMapper {
copy
  • In the mapping file: Cache tag, which specifies the full class name of the cache
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
copy

3, Reverse engineering

MyBatis officially provides a reverse engineering tool to automatically generate the entity classes, mapping files and interfaces corresponding to the table, and automatically realize some basic additions, deletions, modifications and queries

1. Import dependency:
        <!-- Code generation tool jar -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.2</version>
        </dependency>
copy
2. Create generatorconfig. In the resources directory xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="testTables" targetRuntime="MyBatis3">
        <commentGenerator>
            <!-- Remove automatically generated comments true: Yes: false:no -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!--Database connection information: driver class, connection address, user name and password -->
        <!-- <jdbcConnection driverClass="com.mysql.jdbc.Driver"
           connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root"
           password="123">
        </jdbcConnection> -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"
                        userId="root"
                        password="root">
        </jdbcConnection>

        <!-- default false,hold JDBC DECIMAL and NUMERIC Type resolves to Integer,by true Shi Ba JDBC DECIMAL and
           NUMERIC Type resolves to java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- targetProject:generate PO Class location -->
        <javaModelGenerator targetPackage="com.aruba.pojo"
                            targetProject=".\reverseMyBatis\src\main\java">
            <!-- enableSubPackages:Whether to let schema As the suffix of the package -->
            <property name="enableSubPackages" value="false" />
            <!-- The space before and after the value returned from the database is cleaned up -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- targetProject:mapper Location where the mapping file is generated -->
        <sqlMapGenerator targetPackage="com.aruba.mapper"
                         targetProject=".\reverseMyBatis\src\main\java">
            <!-- enableSubPackages:Whether to let schema As the suffix of the package -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- targetPackage: mapper Location of interface generation -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.aruba.mapper"
                             targetProject=".\reverseMyBatis\src\main\java">
            <!-- enableSubPackages:Whether to let schema As the suffix of the package -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>

        <!-- Specify the generated database table -->
        <table tableName="dept" domainObjectName="Dept"
               enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" selectByExampleQueryId="false" >
            <columnOverride column="id" javaType="Integer" />
        </table>

    </context>
</generatorConfiguration>
copy
3. Run the following code:

Manually modify generatorconfig. In the compiled target directory Absolute path to XML

public class GeneratorSqlmap {
    public void generator() throws Exception {
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;

        // Manual modification required
        File configFile = new File("F:\\idelworkspace\\mybatis_study\\reverseMyBatis\\target\\classes\\generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
                callback, warnings);
        myBatisGenerator.generate(null);

    }

    public static void main(String[] args) throws Exception {
        try {
            GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
            generatorSqlmap.generator();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
copy

Generated results:

It comes with some implementations:

public interface DeptMapper {
    int deleteByPrimaryKey(Integer deptno);

    int insert(Dept record);

    int insertSelective(Dept record);

    Dept selectByPrimaryKey(Integer deptno);

    int updateByPrimaryKeySelective(Dept record);

    int updateByPrimaryKey(Dept record);
}
copy

Project address:

https://gitee.com/aruba/mybatis_study.git

Posted by maddali on Wed, 18 May 2022 08:03:38 +0300