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.
- 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; }
- 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(); } }
- 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(); } } }
- Reflection There are some problems in the original Dao development, as follows
- Dao method body has duplicate code: SqlSession is created through SqlSession Factory, and SqlSession's database operation method is invoked.
- 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.
- 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:
- Define namespace in * mapper.xml equal to mapper interface address
- The method name in the mapper interface (Dao interface) should be the same as the id of the state in * mapper.xml.
- 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.
- 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:
- 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; }
- 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>
- 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(); } } }
- 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() ···
- Matters needing attention
The mapper interface method parameters can only have one
Analysis of MyBatis sql execution process
User-oriented Key Object Analysis
- 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.
- 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.
- 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
- 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?)
- Create database links
- Creating Transaction Objects
- Create Executor (Executor)
- 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