MyBatis Quick Start environment setup and single table mapping

  • 2020-06-15 08:54:21
  • OfStack

1. MyBatis profile

When it comes to object relational mapping framework, Hibernate is the first thing that comes to mind. Hibernate is a well-known framework with 10 points of functionality. We just need to configure the relationship between the entity class and the data table, and Hibernate will automatically generate and execute SQL statements and map the result set for us. However, Hibernate is so powerful that it has its disadvantages: 1. It is very bulky, and starting SessionFactory is time-consuming and expensive; 2. 2. Complex configuration, high learning cost, and difficult system tuning; 3 is the custom query function is weak, if the query result is not the mapped entity class, the query will be more troublesome. So another ORM framework, MyBatis, is getting more and more popular.

The disadvantages of Hibernate mentioned above, in turn, are the advantages of MyBatis: 1. 2 is simple in configuration and easy to learn. I intuitively feel that there are fewer official documents than Log4j2. 3 is exactly what MyBatis is all about: mapping query results to be very flexible. Another advantage of MyBatis is that it comes with Chinese documents, which may not be very smooth in some places, but it is enough for us to learn and use.

Configure the environment

1. Dependent introduction

The easiest way to add MyBatis is to use a build tool like Maven or Gradle. I'm using Gradle here. Add the following lines to the project. If you decide not to use the new Java 8 time API, the dependency on line 2 can also be removed. The database I'm using here is MySQL, so I need to add the JDBC driver for MySQL.


compile group: 'org.mybatis', name: 'mybatis', version: '3.4.2'
  compile group: 'org.mybatis', name: 'mybatis-typehandlers-jsr310', version: '1.0.2'
  compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.40'

2. Configuration files

Then we need to write the configuration and mapping files for MyBatis. All of these configuration files are best placed on the classpath, under the src/main/resources folder for Gradle projects. Let's start by writing a configuration file. Please refer to the official documentation for the detailed functions of each section of the configuration file.

Properties section. Define the attributes required for MyBatis here, which can be used in several of the following places. Attributes can also be imported from external properties files.

System Settings. Specify the global configuration of MyBatis here. Detailed configuration participation documentation.

Abbreviated name. The full name of the Java entity class needs to be specified in the mapping file, and we can specify the shorthand name here to simplify the configuration.

The environment. Here we specify the database connection, transaction manager, and so on. You can also specify multiple environments, such as test environment, production environment, that correspond to different database configurations.

Mapping file. Specify the mapping file here, or you can add classes configured with annotations.


  <?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>
    <!-- Specify the attributes -->
    <properties>
      <property name="driver" value="com.mysql.jdbc.Driver"/>
      <property name="url" value="jdbc:mysql://localhost:3306/test"/>
      <property name="username" value="root"/>
      <property name="password" value="12345678"/>
      <property name="driver.useSSL" value="false"/>
    </properties>
    <!-- System Settings -->
    <settings>
      <setting name="cacheEnabled" value="true"/>
      <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
    <!-- Specify a short name -->
    <typeAliases>
      <package name="yitian.study.entity"/>
    </typeAliases>
    <!-- Configure the environment. You can configure multiple environments for testing, debugging, and production -->
    <environments default="development">
      <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
          <property name="driver" value="${driver}"/>
          <property name="url" value="${url}"/>
          <property name="username" value="${username}"/>
          <property name="password" value="${password}"/>
        </dataSource>
      </environment>
    </environments>
    <!-- Configuration mapping file -->
    <mappers>
      <mapper resource="BaseEntityMapper.xml"/>
    </mappers>
  </configuration>

3. Create SqlSessionFactory

With the configuration file in place, we are ready to start using MyBatis. The first thing to do is to create SqlSessionFactory of MyBatis, which, like SessionFactory of Hibernate, is the main factory class, and only one needs to be created per application.
Here is a tool class that simply implements a thread-safe tool class with double check lock. The core code is in the innermost if judgment. Since the configuration file is on the classpath, we only need to specify the file name. Here you use the Resources utility class provided by MyBatis to create 1 input stream and then give it to SqlSessionFactoryBuilder to create 1 SqlSessionFactory.


 public abstract class MyBatisUtils {
    private static volatile SqlSessionFactory sqlSessionFactory;
    public static final String MyBatisConfigLocation = "configuration.xml";
    public static SqlSessionFactory getSqlSessionFactory() throws IOException {
      if (sqlSessionFactory == null) {
        synchronized (MyBatisUtils.class) {
          if (sqlSessionFactory == null) {
            InputStream input = Resources.getResourceAsStream(MyBatisConfigLocation);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(input);
            input.close();
          }
        }
      }
      return sqlSessionFactory;
    }
  }

With SqlSessionFactory created, we are ready to start using MyBatis. Let's step back and see how to create the MyBatis mapping file. Then we continue to use MyBatis.

3. Single table mapping

1. Data tables and entity classes

The mapping file is defined in the mapper section at the end of the configuration file. The mapping file is also something we need to focus on. In the mapping file we need to define various SQL statements and establish their relationships with Java entity classes. Here we use the simplest single table mapping: attribute names are the same between the data table and the entity class, with 11 corresponding.

First, add an entity class.


 public class Person {
    private int id;
    private String username;
    private LocalDate birthday;
  }

The corresponding database table is shown below.


 CREATE TABLE person (
   id    INT AUTO_INCREMENT PRIMARY KEY,
   username VARCHAR(255) NOT NULL UNIQUE,
   birthday DATE
  );

2. Mapping file

Then we write the mapping file. The mapping file contains five SQL statements: add, delete, change, and find by name. Each statement requires an identifier, which will be used later in the code. If resultType is required for a query statement, specify the return type. MyBatis automatically maps the data table listing to the type attributes specified here by name. If you need to pass in a parameter in a statement, you can use the parameterType attribute, specify the full name or abbreviation of the Java entity class, and then use #{} to access the parameter's attribute in the SQL statement. If the mapping is simple, the parameterType attribute can also be omitted, and MyBatis automatically retrieves the corresponding attribute from the Java object passed in. For some databases, such as MySQL, you can also specify useGeneratedKeys="true" at insert time to have the database automatically generate the primary key.


 <?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="yitian.study.dao.mapper">
    <select id="selectPerson"
        resultType="Person" parameterType="Person">
      SELECT *
      FROM Person
      WHERE id = #{id}
    </select>
    <select id="selectPersonByName"
        resultType="Person">
      SELECT *
      FROM Person
      WHERE username = #{username}
    </select>
    <insert id="insertPerson"
        useGeneratedKeys="true">
      INSERT INTO Person (username, birthday) VALUES (#{username}, #{birthday})
    </insert>
    <update id="updatePerson">
      UPDATE Person
      SET birthday = #{birthday}
      WHERE id = #{id}
    </update>
    <delete id="deletePerson">
      DELETE FROM Person
      WHERE id = #{id}
    </delete>
  </mapper>

4. Use MyBatis

With all of this configured, we are ready to use MyBatis. Here we use a unit test to see what MyBatis does. After creating SQLSessionFactory, we need to get MyBatis's core object, SqlSession, to do everything. In addition, it is a non-thread-safe object, cannot be placed on static fields of a class, and preferably not as an instance field. We create it when we need it and release it when we don't.
The commonly used methods include adding, deleting, checking and changing these methods. The first parameter to these methods is the statement ID we defined earlier in the mapping file, and the second parameter is the parameter to pass in. For queries, there are selectOne and selectList methods, which differ mainly in the number of returns, and selectOne if you are certain that only one object will be returned.


 import static org.assertj.core.api.Assertions.*;
  public class MyBatisTest {
    private static SqlSessionFactory sqlSessionFactory;
    private SqlSession sqlSession;
    @BeforeClass
    public static void init() throws IOException {
      sqlSessionFactory = MyBatisUtils.getSqlSessionFactory();
    }
    @Before
    public void before() {
      sqlSession = sqlSessionFactory.openSession(true);// Automatically submit 
    }
    @After
    public void after() {
      sqlSession.close();
    }
    @Test
    public void testMyBatisUtils() {
      assertThat(sqlSessionFactory).isNotNull();
    }
    @Test
    public void testInsert() {
      Person p = new Person(0, "yitian", LocalDate.of(1993, 5, 6));
      sqlSession.insert("insertPerson", p);
      Person s = sqlSession.selectOne("selectPersonByName", p.getUsername());
      assertThat(s).isNotNull();
      System.out.println(s);
      sqlSession.delete("deletePerson", s);
    }
    @Test
    public void testUpdate() {
      Person p = new Person(1, "leo", LocalDate.of(1993, 5, 6));
      sqlSession.insert("insertPerson", p);
      p = sqlSession.selectOne("selectPersonByName", p.getUsername());
      LocalDate b = LocalDate.of(1987, 7, 8);
      p.setBirthday(b);
      sqlSession.update("updatePerson", p);
      Person s = sqlSession.selectOne("selectPersonByName", p.getUsername());
      assertThat(s.getBirthday()).isEqualTo(b);
      System.out.println(s);
      sqlSession.delete("deletePerson", s);
    }
  }

In addition, transaction management for MyBatis is on by default, meaning that we must explicitly use the commit() method to commit the transaction. Auto commit is specified here when SqlSession is opened so that all our changes are immediately reflected in the database.

5. Use mapping classes

In the previous examples, strings were used to specify the query to use. But doing so is inconvenient, strings are error-prone, and IDE's intelligent completion is not available. So MyBatis provides another way to execute SQL statements using mapped classes.
The mapping class is just a simple interface. The methods in this interface correspond to the statement 11 defined in the mapping file. The name of the interface method must be exactly the same as the statement id, and the return value and parameters of the interface method correspond to the corresponding statement.


public interface PersonMapper {
    Person selectPerson(int id);
    Person selectPersonByName(String name);
    void insertPerson(Person person);
    void updatePerson(Person person);
    void deletePerson(Person person);
  }

Adding a mapping class is not enough; we need to modify the mapping file so that MyBatis can find the mapping class. This is done by changing the namespace of the mapping file to the class name of the corresponding mapping file.


<mapper namespace="yitian.study.mapper.PersonMapper">

Once the mapping class is defined and configured, we are ready to use it. Using the method is simple: call the getMapper method on SqlSession and pass in the Mapper class you want to get.


 PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
  Person p = new Person(0, "yitian", LocalDate.of(1993, 5, 6));
  mapper.insertPerson(p);
  Person s = mapper.selectPersonByName(p.getUsername());
  assertThat(s).isNotNull();
  System.out.println(s);
  mapper.deletePerson(p);

With mapped objects, we can access objects in a type-safe manner, while also gaining the completion capabilities of IDE.


Related articles: