Abstract

Recently, I have been studying mybatis framework. As an excellent ORM framework, mybatis has many excellent design ideas worth learning from.

Mybatis configuration files are mainly config and mapper. Config defines global parameters: data source type (POOL, UNPOOLED, JNDI), transaction management type (default: managed), library URL, account information, and mapper file path.

The config configuration

<configuration> <environments default="classfly "> <environment id="classfly "> <transactionManager type="JDBC "/> <dataSource type="POOLED "> <property name="driver " value="com.mysql.jdbc.Driver " /> <property name="url " value="jdbc:mysql://localhost:3306/test? characterEncoding=utf-8 " /> <property name="username " value="yourusername " /> <property name="password " value="yourpassword " /> </dataSource> </environment> </environments> <mappers> <mapper resource="mapper/UserMapper.xml " /> </mappers> </configuration>Copy the code

DBNAME=’test’; DBNAME=’test’;

Mapper configuration

First, we need to ask ourselves three questions:

  • Why configure mapper files?
  • How to configure mapper file?
  • How does Mybatis parse mapper files?

Mapper file function

Mapper file provides a “communication protocol” between the persistence layer and the application layer. It maintains the association relationship between application code DO objects and persistent stored data through mysql keyword resultMap and parameterType.

The mapper file defines four common DML statements, including SELECT, INSERT, update, and delete, and defines statement={mapper namespace}.{operation} to invoke DB operations at the application code layer.

Configure the mapper file

Here are the key parts of the Mapper configuration file used by the test case:

<! - code listing 1 - > < mapper namespace = "com. Classfly. Mapper. UserMapper" > < resultMap id = "user" type = "pojo. User" > < the result column="user_id " property="userId " /> <result column="user_name " property="userName " /> <result column="password " property="password " /> <result column="age " property="age " /> </resultMap> <select id="query " resultMap="user "> SELECT * FROM user; </select> <insert id="insert " parameterType="pojo.User "> insert into user ( user_id, user_name, password, age) values ( #{userId}, #{userName}, #{password}, #{age} ) <selectKey resultType="pojo.User " keyProperty="id " order="AFTER "> select 1313253 as id </selectKey> </insert> <update id="update " parameterType="pojo.User "> UPDATE user SET user_name = #{userName} , password = #{password} , age = #{age} WHERE user_id = #{userId} </update> <delete id="delete "> DELETE FROM user WHERE user_id = #{userId} </delete> </mapper>Copy the code

Mapper namespace defines the scope of DML statements, so what happens if two different Mapper files define the same namespace? Mysql maintains global uniqueness of namespace. Therefore, when parsing mapper files, mysql will throw an exception to prompt developers to modify mapper files to maintain global uniqueness of namespace.

resultMap

The resultMap keyword abstracts the data mapping between the code and the persistence layer, and users do not need to care about how the two are mapped.

We can use HashMap to map the data between the code and the persistence layer, which is not generic and the code layer needs to transform the object into a Map structure. ResultMap accepts the HashMap structure and Javabeans or POJO objects to provide a lightweight parameter mapping scheme.

ResultMap has the “alias” function, so you don’t need to write a bunch of mapping statements for each DML, following the “define once” principle, we can do this:

<resultMap id="userResultMap " type="User ">
  <id property="id " column="user_id " />
  <result property="username " column="user_name "/>
  <result property="password " column="hashed_password "/>
</resultMap>

<select id="query " resultMap="user ">
        SELECT * FROM user
        ORDER BY ${id};
</select>Copy the code

Now if only the world was always that simple!

The ‘#’ and ‘$’

As you can see from “Listing 1”, the placeholder # and the partition are used to implement the projective relation of the P, J, O, and D, B data and the non-transsemantic string. Use ‘role=”presentation “>‘The way the keyword accepts user input can lead to SQL injection attacks, not desirable!

How does Mybatis parse mapper files

To be continued…

The test case

/** * Created by fujianbo on 2018/4/22. * * @author fujianbo * @date 2018/04/22 */ public class TestMybatis { @Test public void testQuery() { SqlSession sqlSession = buildMySqlEnv("config.xml "); List<User> userList = sqlSession.selectList("com.classfly.mapper.UserMapper.query "); for (User p : userList) { System.out.println(p); } } @Test public void testInsert() { SqlSession sqlSession = buildMySqlEnv("config.xml "); User user = new User(); user.setUserId(124L); user.setAge(26); user.setPassword("test_123 "); User. SetUserName (" non-success Rey "); if (sqlSession.insert("com.classfly.mapper.UserMapper.insert ", user) > 0) { sqlSession.commit(); } } @Test public void testUpdate() { SqlSession sqlSession = buildMySqlEnv("config.xml "); User user = new User(); user.setUserId(124L); user.setAge(26); User. SetUserName (" non-success Rey "); user.setPassword("test_modified "); if (sqlSession.update("com.classfly.mapper.UserMapper.update ", user) > 0) { sqlSession.commit(); } } @Test public void testDelete() { SqlSession sqlSession = buildMySqlEnv("config.xml "); User user = new User(); user.setUserId(123L); if (sqlSession.update("com.classfly.mapper.UserMapper.delete ", user) > 0) { sqlSession.commit(); } } private static SqlSession buildMySqlEnv(String resource) { try { return new SqlSessionFactoryBuilder() .build(org.apache.ibatis.io.Resources.getResourceAsStream(resource)) .openSession(); } catch (IOException e) { System.out.printf("Failed to build mysql environment! "); return null; }}}Copy the code

Code link