MyBatis Essay

Mybatis overview


  • This article is only a personal note, not a blog post of knowledge points
  • Encapsulation of the original ecological JDBC program
  • How mybatis develops DAO (two ways):
    • The original DAO method (the program needs to write the DAO interface and implementation class)
    • Mybatis mapper interface (equivalent to DAO interface) proxy development
  • The core of mybatsi:
    • mybatis input mapping
    • mybatis output mapping
  • Dynamic SQL for mybatis
  • mybatis lazy loading
  • mybatis advanced result set mapping
  • Contains a global configuration file and mapping file, such as: mybatis.xml (global configuration file), mapper.xml (mapping file)

Mybatis Framework


  • mybatis is a persistence layer framework under apache, mybatis development is more focused on SQL, and the development is free and flexible
  • mybatsi can automatically perform input mapping to the input parameters in preparedStatement, and flexibly map the query result set to Java objects (output mapping)
  • Create SqlSession through SqlSessionFactory, and operate (CRUD) database through Executor of sqlSession (two types: basic and cached)

Getting Started with Mybatis


  • Development environment:

    • jar package of mybatis
    • log4j.properties (for viewing logs), which can be found in the mabatis configuration file, the development environment is set to the debug level, and the online environment is set to the info level, such as:

      log4j.rootLogger=DEBUG, stdout
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
      
  • Global configuration file mybatis.xml:

    <configuration>
        <!-- 与Spring整合后environment配置将移除 -->
        <environments>
            <environment id="development">
                <!-- 使用jdbc事物管理,事物控制由mybatis -->
                <transactionManager type="JDBC" />
                <!-- 数据库连接池, 由mybatis管理 -->
                <dataSource type="POOLED">
                    <prioperty name="driver" value="..." />
                    <prioperty name="url" value="..." />
                    <prioperty name="username" value="..." />
                    <prioperty name="password" value="..." />
                    <!-- ... -->
                </dataSource>
            </environment>
        </environments>
    
        <!-- 配置映射文件 -->
        <mappers>
            <mapper resource="sqlMapper/User.xml" />
        </mappers>
    </configuration>
    
  • Mapping file User.xml:

    <mapper namesapce="user">
        <!-- 在映射文件中可以配置多个SQL语句对应不同的数据库操作 -->
        <!-- 
            finUserById: 为statement的id
            parameterType:指定输入参数的类型
            resultType:指定输出的结果集映射的Java对象类型
            #{id}: 其中的id表示接收输入的参数,参数名称就是id,如果输入参数是简单类型,#{}中的参数可以任意,可以其他任何名称
            模糊查询使用$符(不建议使用),注意易引起SQL注入,切传入的名称只能是value,如下
        -->
        <select id="findUserById" parameterType="int" resultType="com.demo.User">
            select * from user where id=#{id}
        </select>
        <select id="findUserByName" parameterType="int" resultType="com.demo.User">
            select * from user where username like '%${value}%'
        </select>
    </mapper>
    
  • MySQL gets the self-incrementing id value of the insert, using the last_insert_id() method, such as:

    select last_inser_id()
    
    • The mapped SQL is as follows:

      <insert id="inserUser" parameterType="com.demo.User">
          <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
              select last_insert_id()
          </selectKey>
          insert into user value(#{username}, #{birthday}, #{sex}, #{address})
      </user>
      
  • The essential difference and application scenarios of Mybatis and Hibernate:
    • Hibernate: Standard ORM framework, SQL statements are automatically generated, and it is difficult to optimize SQL statements. It is suitable for small and medium-sized projects with little change in requirements, such as background management systems: erp, orm, oa
    • Mybatis: Focus on SQL itself, need to write SQL, easy to modify and optimize SQL, incomplete ORM framework, suitable for projects with changing requirements, such as Internet projects

How Mybatis develops DAO

  • SqlSessionFactoryBuild creates SqlSessionFactory
  • SqlSessionFactory creates SqlSession, SqlSessionFactory can be created as a single instance
  • SqlSession is not thread-safe, the best application of SqlSession is in the body of the method, that is, it is defined as a local variable
  • DAO development:
    • Original method DAO development:
      • Write the DAO interface
      • Write DAO interface implementation class
    • The mapper proxy method develops DAO:
      • Only need to write the DAO interface, that is, the mapper interface
      • Write the corresponding mapper.xml mapping file
      • Mybatis can automatically generate proxy objects of mapper interface implementation classes
      • Mapper interface development specification:
        • In mapper.xml, the namespace attribute value is equal to the mapper interface address, such as: com.demo.mapper.UserMapper
        • The id of the statement in mapper.xml needs to be the same as the method name of the mapper interface class
        • The type specified by the parameterType of the statement in mapper.xml needs to be consistent with the input parameter type of the method in the mapper interface class
        • The type specified by the resultType of the statement in mapper.xml needs to be consistent with the return value type of the method in the mapper interface class
      • Get the mapper interface proxy object by using the getMapper method of SqlSession
  • Mybatis global configuration file mybatis.xml:

    • properties (attributes): such as database link information
    • settings (global configuration parameters): such as enabling secondary cache, lazy loading, etc.
    • typeAliases: Aliases that can be used to define POJOs, such as:

      <!-- 单个别名定义 -->
      <typeAlias alias="user" type="com.demo.User" />
      <!-- 批量定义别名,别名就是类名首字母小写 -->
      <package name="com.demo" />
      
    • typeHandlers (type handler): completes the conversion of JDBC and Java types
    • objectFactory (object factory):
    • mappers (mapper): load mapping files, load a single mapping file through the resource attribute

      • Use classpath-relative resources:

        <mapper resource="sqlMap/User.xml" />
        
      • Use fully qualified paths:

        <mapper url="file:///D:workspace_20170712\mybatis\sqlMap\User.xml" />
        
      • Use the mapper interface classpath (requires the mapper interface name to be the same as the mapper mapping file name and in the same directory):

        <mapper class="com.demo.mapper.UserMapper" />
        
      • Bulk load resources (requires the same class path as using the mapper interface):

        <package name="com.demo" />
        
  • Output mapping (resultType):
    • Only when the column name or alias of the query is the same as the property name of the POJO can the creation be successful
  • Advanced mapping is done using resultMap:

    • If the queried column name is inconsistent with the POJO attribute name, make a mapping relationship between the column name and the POJO attribute name by defining a resultMap
    • Define resultMap and use resultMap as the output mapping type of the statement

      <!-- type:resultMap最终映射的Java对象类型,可以使用别名
          id:对resultMap的唯一标识
       -->
      <resultMap type="com.demo.User" id="userResultMap">
          <!-- id表示查询结果集中唯一标识,
              column:查询出来的列名
              property:type指定的POJO的属性名
              result表示查询结果集中普通标识
          -->
          <id column="" property="" />
          <result column="" property="" />
      </resultMap>
      

Dynamic SQL

  • Use where and if tags in sql, such as:

    <select id="findUserCount" parameterType="com.demo.User" resultType="int">
        select count(*) from user
        <where>
            <if test="username!=null">
                and user.username="${username}"                
            </if>
            //...               
        </where>
    </select>
    
  • Sql fragment (improves reusability):

    • don't use where tags in sql fragments
    • Use the where subtag include in SQL to refer to sql fragments
    • Such as:

      <sql id="query_user_where">
          <if test="username!=null">
              and user.username="${username}"                
          </if>
          //...   
      </sql>      
      
      <select id="findUserCount" parameterType="com.demo.User" resultType="int">
          select count(*) from user
          <where>
              <include refid="query_user_where" />
          </where>
      </select>
      

Advanced Mapping

  • Map the columns of the relational query to a POJO property (one-to-one)
  • Map the columns of the associated query to a List (one-to-many)
  • The resultMap of the associated query:

    • When querying a single record, use the association tag, such as:

      • JavaBean:

        public class Order{
            private int id;
            private String orderName;
            private User user;
            private List<OrderDetail> orderDetails;
            //....
        }
        
        public class User{
            private int id;
            private String userName;
            private String sex;
            //...
        }
        
      • resultMap:

        <resultMap type="com.demo.Order" id="orderWithUser">
            <id column="order_id" property="id" />
            <result column="order_name" property="orderName" />
        
            <!-- 关联查询的user -->
            <association property="user"  javaType="com.demo.User" >
                <id column="user_id" property="id"/>
                <result column="user_name" property="userName"/>
            </association>
        </resultMap>
        
    • Use the collection tag when querying multiple records, such as:

      <resultMap type="com.demo.Order" id="orderWithUser" extends="orderWithUser">
          <!-- 使用了extends,所示可以省略当前的order属性映射 -->
          <id column="order_id" property="id" />
          <result column="order_name" property="orderName" />
          <collection property="orderDetails" ofType="com.demo.OrderDetail">
              <id column="" property="" />
              <result column="" property="" />
          </collection>
      </resultMap>
      
  • Comparison of resultType and resultMap:
    • resultType is more convenient to use
    • resultMap can implement lazy loading, but resultType can't

lazy loading

  • Association and collection have the function of lazy loading
  • The association uses the select attribute to specify the id of the lazy loaded statement, and uses the column attribute to specify the column name of the associated query
  • Mybatis needs to enable lazy loading, the default is not enabled, the following way to enable lazy loading in the global configuration file:

    <settings>
        <setting name="lazyLoadingEnabled" value="true" />
        <setting name="aggressiveLazyLoading" value="false" />
    <settings>
    

query cache

  • Level 1 cache - SqlSession level cache
    • There is a data structure (HashMap) in the SqlSeesion object for storing cached data, and the cache areas between different SqlSessions do not affect each other
    • After the SqlSession executes the commit operation (insert, update, delete), it will clear the first level cache in the SqlSession
    • mybatis supports first level cache by default
  • L2 cache - Mapper level cache

    • Multiple SqlSessions operate the SQL statements of the same Mapper, and the second-level cache is across SqlSessions
    • The second level cache of mybatis needs to be manually opened
    • The cache area of ​​the second-level cache is distinguished by namespace, that is, there is a second-level cache area for each namespace mapper
    • The opening of the second-level cache needs to be configured in the global configuration file, and also needs to be set in the configuration file of the mapper that needs to be turned on

      • The configuration in the global file is as follows:

        <setting name="cacheEnabled" value="true" />
        
      • The configuration in the Mapper configuration file is as follows:

        <!-- 其中的type属性可以设置自定义的Cache实现类或第三方框架的Cache实现类 -->
        <cache />   
        
    • The corresponding POJO class should implement the serialization interface in order to fetch the cached data and implement the deserialization operation, because the data storage medium of the second-level cache is not necessarily in memory
    • Only after SqlSession performs the close operation can the data be saved to the secondary cache
    • Use the useCache property to disable the second-level cache, and use flushCache to refresh (empty) the second-level cache. The default value is true, such as:

      <select id="findUserById" resultType="com.demo.User" useCache="false">
          //sql...
      </select>
      
  • Ehcache, redis, memcached is a distributed caching framework
  • Mybatis provides a cache interface to implement a custom cache mechanism. The default Cache class implemented by Mybatis is PrepetualCache. When developing custom cache logic, you can refer to the default Cache class implementation.
  • When using the ehcache framework, you need to configure the corresponding ehcache file:

  • The first level cache is for one SqlSession, and the second level cache is for multiple SqlSessions

Mybatis integrates Spring

  • Mybatis and Spring integration - sqlSessionFactory configuration

    • The mapper of the persistence layer needs spring management, and spring needs to manage the sqlSessionFactory through a singleton
    • Integration environment (jar package):
      • mybatis
      • spring
      • The integration package of mybatis and spring (mybatis-spring.jar)
    • Configure sqlSessionFactory in spring's configuration file (applicationContext.xml)

      <!-- 加载配置文件 -->
      <context:property-placeholder location="classpath:db.property" />
      <!-- 数据库连接池 -->
      <bean id="dataSource" class="">
          <property name="" value="" />
          <!-- 数据源的信息 -->
      </bean>
      <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
          <property name="configLocation" value="mybatis.xml" />
          <!-- dataSource -->
          <property name="dataSource" ref="dataSource" />
      </bean>
      
  • The original DAO development after the integration of mybatis and spring:

    • Create mapper.xml mapping file and DAO interface and its implementation class
    • Load map files via mappers element in global file
    • When creating a DAO implementation class, make it inherit the SqlSessionDaoSupport class, so that there is no need to declare the SqlSessionFactory property displayed in the implementation class class, and use this.getSqlSession() in the DAO method to obtain the SqlSession, as follows:

      public class UserDAOImpl extends SqlSessionDaoSupport implements UserDAO{
          public User findUserById(int id){
              SqlSession sqlSession = this.getSqlSession();
              //操作数据库,方法结束自动关闭sqlSession,不需要显示close
              return user;
          }
      }
      
      在spring配置文件中配置DAO:
      <bean id="userDAO" class="com.demo.mm.dao.UserDAOImpl">
              <property name="sqlSessionFactory" ref="sqlSessionFactory" />
      </bean>
      
  • Mapper proxy development after mybatis and spring integration:

    • Create the Mapper interface class and its mapper.xml file
    • Configure mapper in spring's configuration file and create proxy objects through MapperFactoryBean:

      <!-- MapperFactoryBean根据mapper接口生成代理对象 -->
      <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
          <!-- 指定mapper接口, mapperInterface为MapperFactoryBean的属性名 -->
          <property name="mapperInterface" value="com.demo.mm.mapper.UserMapper" />
          <property name="sqlSessionFactory" ref="sqlSessionFactory" />
      </bean>
      
    • Batch configuration of mapper, scan mapper interface from mapper package, automatically create proxy object and register in spring container (recommended):

      <!-- 在spring中加入mapper扫描后,在mybatis的配置文件中就不需要再加入扫描mapper -->
      <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
          <!-- 
              1.指定扫描的包名,basePackage为MapperScannerConfigurer类中的属性名 
              2.mapper.java与mapper.xml的文件名需要保持一致,且在同一目录中
              3.如果扫描多个包不能使用通配符,只能使用逗号分隔
          -->
          <property name="basePackage" value="com.demo.mm.mapper" />
          <!-- 此处不能使用sqlSessionFactory -->
          <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
      </bean> 
      

Reverse Engineering

  • Mybatis officially provides reverse engineering, which can automatically generate the code required for mybatis execution for a single table, as follows:
    • mapper.java
    • mapper.xml
    • POJO class
  • In actual development, the commonly used reverse engineering method is to generate java code from database tables
  • Download mybatis reverse engineer:
    • mybatis-generator-core-(version)-bundle
  • Use of reverse engineering:
    • Ways to use Java programs and XML configuration files
  • For specific configuration, refer to the official documentation

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325820928&siteId=291194637