MyBatis - use of basic annotations

Keywords: Mybatis

0. Project construction

Still the same, let's build a new project first   mybatis-04-annotation  , Copy and paste all the files from the previous project and simplify them.

Streamlined code, just streamline it   mybatis-config.xml   You can:

<?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>
    <settings>
        <setting name="logImpl" value="LOG4J"/>
        <setting name="cacheEnabled" value="true"/>
    </settings>

    <typeAliases>
        <package name="com.linkedbear.mybatis.entity"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mapper/department.xml"/>
        <mapper resource="mapper/user.xml"/>
    </mappers>
</configuration>

The rest of the code can be simplified freely according to their actual practice. The booklet has not been simplified too much, but some redundant resultmaps have been deleted.

In addition, we need to create two new Mapper interfaces to replace the original Mapper interface   DepartmentMapper   and   UserMapper  :

public interface DepartmentAnnotationMapper {
    
}

public interface UserAnnotationMapper {
    
}

Remember to configure it into MyBatis global configuration file after creation:

<mappers>
    <mapper resource="mapper/department.xml"/>
    <mapper resource="mapper/user.xml"/>
    <mapper class="com.linkedbear.mybatis.mapper.DepartmentAnnotationMapper"/>
    <mapper class="com.linkedbear.mybatis.mapper.UserAnnotationMapper"/>
</mappers>

OK, now we're ready to start. In MyBatis version 3.0, there is an annotation driven mapper. We can use annotations to define statements, which seems more simple and convenient. However, due to some limitations of Java language features, MyBatis does not have a particularly good way to build a very powerful result set mapping (it is not possible to configure resultMap as flexibly as in mapper.xml). However, annotation based statement definition provides a convenient and low-cost way.

In this chapter, we first review the basic annotation usage in MyBatis.

1. @Select

@Select   Annotation, similar to the most common annotation in mapper.xml  < select>   Tag, which is one of the most basic annotations. We can first give a few simple examples to help you quickly review and get started  @ Select   Use of annotations.

1.1 basic single table query

A simple single table query can't be simpler. You only need to declare one   findAll   Method and mark on the method  @ Select   Notes, write SQL and you're done:

public interface DepartmentAnnotationMapper {
    
    @Select("select * from tbl_department")
    List<Department> findAll();
}

Although it is so simple, in fact, after it is written in this way, compared with the elements that need to be provided to define a statement in mapper.xml, it is simply a lot:

  • findAll   → id of select
  • List<Department> → resultType
  • DepartmentAnnotationMapper   Fully qualified class name → namespace
  • SQL

After writing this, we can directly write test classes to run:

public class AnnotationMapperApplication {
    
    public static void main(String[] args) throws Exception {
        InputStream xml = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(xml);
        SqlSession sqlSession = sqlSessionFactory.openSession();
    
        DepartmentAnnotationMapper departmentMapper = sqlSession.getMapper(DepartmentAnnotationMapper.class);
        List<Department> departmentList = departmentMapper.findAll();
        departmentList.forEach(System.out::println);
    }
}

function   main   Method, the console can print all department information normally:

Department{id='00000000000000000000000000000000', name='All departments', tel='-'}
Department{id='18ec781fbefd727923b0d35740b177ab', name='Development Department', tel='123'}
Department{id='53e3803ebbf4f97968e0253e5ad4cc83', name='Test product department', tel='789'}
Department{id='ee0e342201004c1721e69a99ac0dc0df', name='Operation and maintenance department', tel='456'}

It shows that everything is feasible.

1.2 attached input

Like the previous routine developed with Mapper dynamic agent, declare method parameters on Mapper interface and reference parameters in SQL:

    @Select("select * from tbl_department where id = #{id}")
    Department findById(String id);

Similarly, let's write the test code:

    Department department = departmentMapper.findById("18ec781fbefd727923b0d35740b177ab");
    System.out.println(department);

function   main   Method test, the console can print successfully:

Department{id='18ec781fbefd727923b0d35740b177ab', name='Development Department', tel='123'}

1.3 writing complex SQL

findAll   The method is the most basic single table query, but more often, SQL is spliced dynamically according to an example object. But here comes the problem: @ Select   How to judge in the annotation?

Unfortunately, this is what the MyBatis official document says. They really can't handle the preparation of this complex SQL. They can only use the form similar to script to write dynamic SQL similar to that in mapper.xml. The booklet first gives an example:

    @Select("<script>select * from tbl_department "
                    + "<where>"
                    + "<if test='id != null'>and id = #{id} </if>"
                    + "<if test='name != null'>and name like concat('%', #{name}, '%') </if>"
                    + "<if test='tel != null'>and tel = #{id} </if>"
                    + "</where>"
                    + "</script>")
    List<Department> findAllByExample(Department example);

Oh, it looks too bad! Even if there is no prompt, the string is spelled. You can't see it... So that's why MyBatis officials say that complex SQL is not recommended to be written with an annotation mapper.

Well, let's put aside the hot eyes, let's test the effect first:

    Department example = new Department();
    example.setName("whole");
    List<Department> departmentListByExample = departmentMapper.findAllByExample(example);
    System.out.println(departmentListByExample);

Run the test code, and the SQL and query results printed on the console meet the expectations:

[main] DEBUG otationMapper.findAllByExample  - ==>  Preparing: select * from tbl_department WHERE name like concat('%', ?, '%') 
[main] DEBUG otationMapper.findAllByExample  - ==> Parameters: whole(String) 
[main] DEBUG otationMapper.findAllByExample  - <==      Total: 1 
[Department{id='00000000000000000000000000000000', name='All departments', tel='-'}]

1.4 manually configure result set mapping

Like mapper.xml, if the query result requires us to manually configure the result set mapping, it is also possible to use annotations, but the configuration method is hot...

1.4.1 configuration example

Let's write an example in the following booklet:

    @Select("select * from tbl_department")
    @Results({
        @Result(id = true, property = "id", column = "id"),
        @Result(property = "name", column = "tel"),
        @Result(property = "tel", column = "name")
    })
    List<Department> findAllByResults();

As shown in the above code, @ Results   Annotations can be compared  < resultMap>   Label, each  @ Result   Annotations can be compared  < id>   perhaps  < result>   label. This is acceptable for simple result set mapping.

Next, we can still write the following test code to verify whether the configured result set mapping is effective:

    List<Department> departmentByResultsList = departmentMapper.findAllByResults();
    departmentByResultsList.forEach(System.out::println);

function   main   Method to find the information printed in the console   Department   Object   name   Attribute and   tel   It's true that the configuration has been changed, indicating that there is no problem with this configuration.

Department{id='00000000000000000000000000000000', name='-', tel='All departments'}
Department{id='18ec781fbefd727923b0d35740b177ab', name='123', tel='Development Department'}
Department{id='53e3803ebbf4f97968e0253e5ad4cc83', name='789', tel='Test product department'}
Department{id='ee0e342201004c1721e69a99ac0dc0df', name='456', tel='Operation and maintenance department'}

1.4.2 result set mapping reuse

Maybe the careful little partner found a problem: configure the result set mapping in the above configuration way, isn't it for everyone  @ Select   Do you need to write it all? It did need this in the early MyBatis, but fortunately after MyBatis version 3.3.1, @ Results   One more annotation   id   Property so that you can use another annotation  @ ResultMap  , And declare   id   Attribute refers to the defined result set mapping, so as to reuse the result set mapping.

    @Select("select * from tbl_department")
    @Results(id = "departmentUseResultsId", value = {
        @Result(id = true, property = "id", column = "id"),
        @Result(property = "name", column = "tel"),
        @Result(property = "tel", column = "name")
    })
    List<Department> findAllByResults();

    @Select("select * from tbl_department")
    @ResultMap("departmentUseResultsId")
    List<Department> findAll();

Then we can test it again   findAll   Method. Only the logs and running results printed on the console after the test are posted in the booklet. It can be seen that the resultMap has indeed been successfully referenced:

[main] DEBUG rtmentAnnotationMapper.findAll  - ==>  Preparing: select * from tbl_department 
[main] DEBUG rtmentAnnotationMapper.findAll  - ==> Parameters:  
[main] DEBUG rtmentAnnotationMapper.findAll  - <==      Total: 5 
Department{id='00000000000000000000000000000000', name='-', tel='All departments'}
Department{id='18ec781fbefd727923b0d35740b177ab', name='123', tel='Development Department'}
Department{id='53e3803ebbf4f97968e0253e5ad4cc83', name='789', tel='Test product department'}
Department{id='ee0e342201004c1721e69a99ac0dc0df', name='456', tel='Operation and maintenance department'}

Of course, if it is used in actual development   XML + annotation   During mixed development of @ resultMap   Annotations can also be used   namespace + resultMap id   The fully qualified name of refers to the resultMap defined in mapper.xml.

2. DML notes

Let's use the corresponding DML statement again  @ Insert  ,@ Update  ,@ Delete   Notes.

2.1 @Insert

2.1.1 basic use

@Insert   The use of the annotation itself is very simple. We can quickly write a test code and try it:

    @Insert("insert into tbl_department (id, name, tel) values (#{id}, #{name}, #{tel})")
    int save(Department department);

Correspondingly, when testing, you need to construct a   Department  , Then execute   save   Method (don't forget to commit the transaction last):

    Department department = new Department();
    department.setId(UUID.randomUUID().toString().replaceAll("-", ""));
    department.setName("Testing department~");
    department.setTel("123456789");
    departmentMapper.save(department);
    // The transaction will not take effect until it is committed
    sqlSession.commit();
    sqlSession.close();

Then we can run   main   The method has tested the effect:

[main] DEBUG DepartmentAnnotationMapper.save  - ==>  Preparing: insert into tbl_department (id, name, tel) values (?, ?, ?) 
[main] DEBUG DepartmentAnnotationMapper.save  - ==> Parameters: 11c8cdec37e041cf8476c86d46a42dd3(String), Testing department~(String), 123456789(String) 
[main] DEBUG DepartmentAnnotationMapper.save  - <==    Updates: 1 

The insert statement was executed successfully, and the data was successfully inserted into the database:

2.1.2 need to return primary key

As in the previous chapter 8, the self increment attribute may be used for the primary key of the database table when inserting data, so the primary key needs to be backfilled into the entity class object after the insertion is completed. There is a special door in MyBatis annotation  @ Options   Attribute, which can be compared with most attributes used in all statement tags(   useCache  , flushCache  , timeout   Etc.).

So in this way, we can define a new statement and configure it   useGeneratedKeys   and   keyProperty  , This is similar to what is written in mapper.xml:

    @Insert("insert into tbl_dept2 (name, tel) values (#{name}, #{tel})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int saveUseGeneratedKeys(Department department);

Note that the configuration is   keyProperty   Oh, don't configure it incorrectly   keyColumn  , So there's no way.

OK, similarly, let's quickly write the test code:

    Department department = new Department();
    department.setName("Testing department~");
    department.setTel("123456789");
    departmentMapper.saveUseGeneratedKeys(department);
    System.out.println(department);
    // The transaction will not take effect until it is committed
    sqlSession.commit();
    sqlSession.close();

Run the test code and observe the department printed in the console:

[main] DEBUG saveUseGeneratedKeys  - ==>  Preparing: insert into tbl_dept2 (name, tel) values (?, ?) 
[main] DEBUG saveUseGeneratedKeys  - ==> Parameters: Testing department~(String), 123456789(String) 
[main] DEBUG saveUseGeneratedKeys  - <==    Updates: 1 
Department{id='7', name='Testing department~', tel='123456789'}

id has been successfully backfilled, indicating that everything is successful.

2.2 @Update and @ Delete

about  @ Update   and  @ Delete   There aren't so many ways, after all, they don't  @ Result   Such annotations can be used directly:

    @Update("update tbl_department set name = #{name} where id = #{id}")
    int updateById(Department department);
    
    @Delete("delete from tbl_department where id = #{id}")
    int deleteById(String id);

Then we can write some test code to see the effect:

    Department department = departmentMapper.findById("11c8cdec37e041cf8476c86d46a42dd3");
    department.setName("Test and test");
    departmentMapper.updateById(department);

    departmentMapper.deleteById("11c8cdec37e041cf8476c86d46a42dd3");

    sqlSession.commit();
    sqlSession.close();

The end result must be   id   by   11c8cdec37e041cf8476c86d46a42dd3   Our department has been deleted. We just need to look at the console and print the SQL normally.

[main] DEBUG Mapper.updateById  - ==>  Preparing: update tbl_department set name = ? where id = ? 
[main] DEBUG Mapper.updateById  - ==> Parameters: Test and test(String), 11c8cdec37e041cf8476c86d46a42dd3(String) 
[main] DEBUG Mapper.updateById  - <==    Updates: 1 
[main] DEBUG Mapper.deleteById  - ==>  Preparing: delete from tbl_department where id = ? 
[main] DEBUG Mapper.deleteById  - ==> Parameters: 11c8cdec37e041cf8476c86d46a42dd3(String) 
[main] DEBUG Mapper.deleteById  - <==    Updates: 1 

The rest is nothing to talk about. The use of annotations is still very simple.

3. @Options

At the end of this chapter, let's mention one mentioned above  @ Options   Annotation, it is to supplement  @ Select  ,@ Insert  ,@ Update  ,@ Delete   The same attribute configuration in the annotation, as mentioned in mapper.xml, these statement tags have many attributes (such as   useCache  , flushCache  , timeout  ), The following booklet lists the attributes. Let's see if everyone is familiar with them:

boolean useCache() default true;
FlushCachePolicy flushCache() default FlushCachePolicy.DEFAULT;
ResultSetType resultSetType() default ResultSetType.DEFAULT;
StatementType statementType() default StatementType.PREPARED;
int fetchSize() default -1;
int timeout() default -1;
boolean useGeneratedKeys() default false;
String keyProperty() default "";
String keyColumn() default "";
String resultSets() default "";
String databaseId() default "";

You can see that the attributes can be found in the attributes of several statement tags in mapper.xml!

 

Posted by Forever_xxl on Sat, 20 Nov 2021 18:41:11 -0800