MyBatis from Shallow to Deep (Practice) - 2

Posted by terryl on Mon, 27 May 2019 00:53:58 +0200

MyBatis Develops DAO(Data Access Object)

Two ideas:

  • Original Dao Development Method (Writing Dao Interface and Interface Implementation Class DaoImpl, respectively)
  • With MyBatis, proxy development using mapper interface (equivalent to Dao interface)

Expected function

Implementing CRUD of Single Table with Dao Interface

Example program

Primitive Dao Development

Train of thought: Design the Dao interface, inject SqlsessionFactory into the Dao implementation class, create SqlsessionFactory in the method body and execute the corresponding sql through SqlsessionFactory.

  1. Designing Dao Interface
import cn.guan.mybatis.example2.User;

/**
 * User Dao Interface definition
 * @Created 2017/9/7.
 */
public interface UserDao {

    //Query user information based on id
    User findUserById(int id) throws Exception;

    //Adding user information
    void addUser(User user) throws Exception;

    //Delete user information
    void deleteUser(int id) throws Exception;

}
  1. Implementation of Dao Interface
import cn.guan.mybatis.example2.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

/**
 * User Dao Implementation class
 * @Created 2017/9/7.
 */
public class UserDaoImpl implements UserDao{

    //SqlsessionFactory needs to be injected into the Dao implementation class
    //Here we inject it through the construction method.
    private SqlSessionFactory sqlSessionFactory;

    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    @Override
    public User findUserById(int id) throws Exception {
        //Create Sqlsession in the method body through SqlsessionFactory
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("test.findUserById", id);
        sqlSession.close();
        return user;
    }

    @Override
    public void addUser(User user) throws Exception {
        //Create Sqlsession in the method body through SqlsessionFactory
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //Perform insert operations
        sqlSession.insert("test.insetrUser", user);
        //Submission of affairs
        sqlSession.commit();
        //Release resources
        sqlSession.close();
    }

    @Override
    public void deleteUser(int id) throws Exception {
        //Create Sqlsession in the method body through SqlsessionFactory
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.delete("test.deleteUserById", id);
        //Submission of affairs
        sqlSession.commit();
        sqlSession.close();
    }
}
  1. functional testing
import cn.guan.mybatis.example2.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.text.SimpleDateFormat;

/**
 * Original dao test
 * @Created 2017/9/7.
 */
public class UserDaoImplTest {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() throws Exception
    {
        //Create sqlSessionFactory
        //Mybatis configuration file
        String resource = "mybatis-config.xml";
        //Get the configuration file stream
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //Create a session factory and pass in Mybatis configuration file information
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void testFindUserById() throws Exception
    {
        //Create UserDao objects
        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        //Call the UserDao method
        User user = userDao.findUserById(1);
        System.out.println(user);
    }

    @Test
    public void testAddUser(){
        //Create UserDao objects
        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        try {
            User user = new User();
            user.setUsername("Zhao Liu");
            //To set date input for birthday
            SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd");
            user.setBirthday(sdf.parse("2005-01-12"));
            user.setSex("male");
            user.setAddress("Changsha, Hunan");

            userDao.addUser(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testDeleteUser(){
        //Create UserDao objects
        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        try {
            userDao.deleteUser(3);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

  1. Reflection There are some problems in the original Dao development, as follows
  1. Dao method body has duplicate code: SqlSession is created through SqlSession Factory, and SqlSession's database operation method is invoked.
  2. Calling sqlSession's database operation method requires specifying the id of the state, where there is hard coding, which is not suitable for development and maintenance.
  3. Variables passed in when calling sqlSession's database operation method, because sqlsession method uses generic type, even if the variable type is passed in errors, it will not report errors in the compilation stage, which is not conducive to programmer development.

Using Mybatis's mapper interface to develop Dao

Train of thought: Write * mapper.xml Mapping file, design mapper interface (equivalent to Dao interface), follow MyBatis mapper interface development specifications, the framework automatically generates proxy objects of mapper interface class, automatically calls the corresponding sql in * mapper.xml

mapper Interface Development Specification:

  1. Define namespace in * mapper.xml equal to mapper interface address
  2. The method name in the mapper interface (Dao interface) should be the same as the id of the state in * mapper.xml.
  3. The input parameter type in the mapper interface (Dao interface) should be the same as the parameter type specified by the parameterType in * mapper.xml.
  4. The return value type in the mapper interface (Dao interface) should be the same as the type specified in the resultType in * mapper.xml.

Realization:

  1. Designing mapper interface
import cn.guan.mybatis.example2.User;

import java.util.List;

/**
 * User Mapper Interface definition
 * @Created 2017/9/7.
 */
public interface UserMapper {

    //Query user information based on id
    User findUserById(int id) throws Exception;

    //Query user information based on id
    List<User> findUserByUsername(String username) throws Exception;

    //Adding user information
    void insertUser(User user) throws Exception;

    //Delete user information
    void deleteUserById(int id) throws Exception;

}
  1. Write * mapper.xml and add it to the global configuration file (mybatis-config.xml)

Write user-mapper.xml:

<?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">

<!--namespace : Namespace, right sql Classified management for isolation sql Sentence-->
<!--Namespaces are set to mapper Interface address  -->
<mapper namespace="cn.guan.mybatis.example3.UserMapper">
    <!-- according to id Getting User Information -->
    <select id="findUserById" parameterType="int" resultType="cn.guan.mybatis.example2.User">
        select * from tb_user where id = #{id}
    </select>

    <select id="findUserByUsername" parameterType="java.lang.String" resultType="cn.guan.mybatis.example2.User">
        select * from tb_user where username like '%${value}%'
    </select>

    <!-- Add user -->
    <insert id="insertUser" parameterType="cn.guan.mybatis.example2.User">
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
            select LAST_INSERT_ID()
        </selectKey>
        insert into tb_user(username, birthday, sex, address)
        values(#{username}, #{birthday}, #{sex}, #{address})
    </insert>

    <!--delete user-->
    <delete id="deleteUserById" parameterType="int">
        delete from tb_user where id = #{id}
    </delete>

    <!--according to id Update user-->
    <update id="updateUserById" parameterType="cn.guan.mybatis.example2.User">
        update tb_user set username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} where id = #{id}
    </update>

</mapper>

User-mapper.xml is configured to the global configuration mybatis-config.xml, and user-mapper.xml is loaded at project runtime

<?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>
    <!-- and spring After integration environments Configuration will be abolished-->
    <environments default="development">
        <environment id="development">
            <!-- Use jdbc transaction management,Transaction by Mybatis control-->
            <transactionManager type="JDBC" />
            <!-- Database connection pool,from Mybatis Administration, db_mybatis,Mysql User name root,123456 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/db_mybatis?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>

    <!--Load mapper File path-->
    <mappers>
        <mapper resource="mapperDir2/user-mapper.xml" />
    </mappers>
</configuration>
  1. functional testing
import cn.guan.mybatis.example2.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.List;

/**
 * Testing MyBatis mapper interface to implement Dao 
 * @Created 2017/9/7.
 */
public class UserMapperTest {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() throws Exception
    {
        //Create sqlSessionFactory
        //Mybatis configuration file
        String resource = "mybatis-config.xml";
        //Get the configuration file stream
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //Create a session factory and pass in Mybatis configuration file information
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void testFindUserById() throws Exception
    {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //Create usermapper objects, mybatis automatically generates proxy objects
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //Calling the UserMapper method
        User user = userMapper.findUserById(4);
        System.out.println(user);
    }

    @Test
    public void testFindUserByUsername(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //Create usermapper objects, mybatis automatically generates proxy objects
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //Calling the UserMapper method
        try {
            List<User> users = userMapper.findUserByUsername("Zhao");
            System.out.println(users == null ? "[null]":users.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testAddUser(){
        //Set sqlSession to turn on automatic submission
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //Create usermapper objects, mybatis automatically generates proxy objects
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        try {
            User user = new User();
            user.setUsername("Zhao Liu Yi");
            //To set date input for birthday
            SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd");
            user.setBirthday(sdf.parse("2001-01-12"));
            user.setSex("male");
            user.setAddress("Yueyang, Hunan");

            userMapper.insertUser(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testDeleteUser(){
        //Set sqlSession to turn on automatic submission
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //Create usermapper objects, mybatis automatically generates proxy objects
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        try {
            userMapper.deleteUserById(7);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

  1. Reflection

mapper solves the following problems: Following the mapper interface development specification, calls to SqlSession interface methods will be generated uniformly by MyBatis

sqlSession.selectOne()
sqlSession.selectList()
sqlSession.insert()
sqlSession.delete()
sqlSession.update()
···
  1. Matters needing attention

The mapper interface method parameters can only have one

Analysis of MyBatis sql execution process

User-oriented Key Object Analysis

  1. SqlSessionFactoryBuilder SqlSession Factory Builder is used to create SqlSession Facoty. Once SqlSession Facoty is created, SqlSession Factory Builder is not needed. Because SqlSession is produced by SqlSession Factory, SqlSession Factory Builder can be used as a tool class. The best use range is method scope, that is, local variables in the method body.
  2. SqlSessionFactory SqlSession Factory is an interface that defines different overloading methods of openSession. The best use of SqlSession Factory is the whole application running period. Once created, SqlSession Factory can be reused. Usually, SqlSession Factory can be managed in a singleton mode.
  3. SqlSession SqlSession encapsulates database operations, such as query, insert, update, delete, etc. SqlSession is created through SqlSession Factory, and SqlSession Factory is created through SqlSession Factory Builder. SqlSession is a user-oriented interface. The database operation is defined in sqlSession, and the DefaultSqlSession implementation class is used by default.

SQL execution process

  1. Load configuration information (mybatis-config.xml,* mapper.xml)

mybatis-config.xml global configuration

  • Data Source Information
<environments ···>
	<! - Data Source Environment Configuration - >
	<environment ···>
		<! - Transaction Manager - >
		<transactionManager ··· />
		<! - Data Source Configuration - >
		<dataSource ···>
			<property ··· />
			···
		</dataSource>		
	</environment>
</environments>
  • mapper interface and sql mapping file address
<!-- *mapper.xml File address -->
<mappers>
	<mapper ··· />
	···
</mappers>

* mapper.xml defines the corresponding sql for mapper interface, and the mapping relationship between parameters, return data and java objects

<mapper namespace="Namespace">
	<insert ···>
	<delete ···>
	<update ···>
	<select ···>
	<sql ···>
	···
</mapper>

By looking at the DTD file of mybatis config file (http://mybatis.org/dtd/mybatis-3-mapper.dtd), you can see that the tags supported under configuration in mybatis-config.xml are as follows

configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, >reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)
  1. Create database links
  2. Creating Transaction Objects
  3. Create Executor (Executor)
  4. The implementation class of SqlSession, DefaultSqlSession, essentially uses Executor to manipulate the database.

Note: For space reasons, here is only a brief introduction to the implementation process, which will be analyzed in detail later.

Matters needing attention

Instances of SqlSession cannot be shared. It is thread insecure, so each thread should have its own SqlSession instance. So the best scope is the request or method scope (defining the use of local variables). References to SqlSession instances must never be placed in static or instance fields of a class. Open a SqlSession; close it when you're done with it. Usually this closing operation is placed in the final block to ensure that the closing can be performed every time.

SqlSession session = sqlSessionFactory.openSession();
try {
     // do work
} finally {
    session.close();
}

Reference link: http://blog.csdn.net/column/details/13905.html

Topics: Mybatis xml Session SQL