MyBatis隨筆

前一陣參與了一個項目的搭建,爲了快速開發再加上學一些新東西,準備採用React+Spring MVC+MyBatis的架構。java

花了一些時間最終把Spring MVC+MyBatis打通。面試

這裏總結下MyBatis的使用過程,方便之後查閱。spring

 

 參考資料:sql

1. http://www.mybatis.org/mybatis-3/zh/數據庫

2. http://blog.csdn.net/isea533/article/category/2092001apache

 

不玩兒虛的,直接上!session

環境:Intellij IDEA 12; SQLSERVER;mybatis

既然是Spring MVC+MyBatis的架構,分service和persistence層。另外,Intellij IDEA構建多模塊結構仍是挺方便的,兩個模塊以下:架構

總體的運做就是service層調用persistence層的dao來訪問數據庫,而MyBatis則做爲數據庫SQLSERVER同service層的橋樑。app

MyBatis總體來講,同Hibernate同樣,是對JDBC的輕量級封裝,完成ORM功能。

從使用MyBatis和Hibernate來講,我的感受,Hibernate更加偏向於對象化,好比Criteria和Query,建立查詢對象;MyBatis則偏向於sql,將sql語句寫入mapper文件中。

整體來講,使用Hibernate須要多多少少了解它的HQL語句,而MyBatis則更注重數據庫操做的專注化,即只是使用sql語句,對查詢結果用resultMap封裝,因此難易程度上,我的感受MyBatis更容易一些。

 

下面試着打通MyBatis和SQLSERVER......

1. 任何開源框架的使用,確定是要先進行配置的。

  1.1 對MyBatis來講,針對它本身的配置文件是mybatisConfig.xml(默認)。在這個項目裏,由於和Spring整合,就只用到日誌的配置。

mybatisConfig.xml

<?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>
    <settings>
        <setting name="logImpl" value="SLF4J"/>
    </settings>
</configuration>

這裏對應logImpl的value能夠從源碼裏找到(org.apache.ibatis.session.Configuration, 該類配置了不少MyBatis的默認值),以下:

    typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
    typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
    typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
    typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
    typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
    typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
    typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);

  1.2 由於同Spring整合,添加mybatis-spring依賴(maven方式)

            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>1.3.0</version>
            </dependency>

  1.3 回到數據庫一端,涉及建立數據源以及基於Spring的事務管理

persistence.properties

# jdbc.*
jdbc.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc.url=jdbc:sqlserver://dbhost:dbport;databaseName=db-name;
jdbc.user=aaa
jdbc.password=aaa
jdbc.initialSize=1
jdbc.minIdle=1
jdbc.maxActive=20
jdbc.maxWait=60000
jdbc.tberm=60000
jdbc.meitm=300000
jdbc.vq=SELECT 'x'
jdbc.twi=true
jdbc.tob=false
jdbc.tor=false

persistenceContext.xml (Part I)

<context:property-placeholder location="classpath:persistence.properties"/>
    <!-- DataSource related -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="initialSize" value="${jdbc.initialSize}"/>
        <property name="minIdle" value="${jdbc.minIdle}"/>
        <property name="maxActive" value="${jdbc.maxActive}"/>
        <property name="maxWait" value="${jdbc.maxWait}"/>
        <property name="timeBetweenEvictionRunsMillis" value="${jdbc.tberm}"/>
        <property name="minEvictableIdleTimeMillis" value="${jdbc.meitm}"/>
        <property name="validationQuery" value="${jdbc.vq}"/>
        <property name="testWhileIdle" value="${jdbc.twi}"/>
        <property name="testOnBorrow" value="${jdbc.tob}"/>
        <property name="testOnReturn" value="${jdbc.tor}"/>
    </bean>
<!-- 配置Spring的事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager" />

這裏的jdbc.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver,SQLServerDriver並無在Maven Repository託管,並且鑑於項目基於Maven構建,將下載到的sqljdbc41.jar(jre7) install到本地,使用以下命令:

mvn install:install-file -Dfile=sqljdbc41.jar -Dpackaging=jar -DgroupId=com.microsoft.sqlserver -DartifactId=sqljdbc -Dversion=4.1

OK, 接下來是mybatis同Spring整合時的核心部分。

  1.4 Mybatis同Spring整合

persistenceContext.xml (Part II)

    <!-- 配置sqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
        <property name="configLocation" value="classpath:mybatisConfig.xml"/>
        <property name="typeAliasesPackage" value="com.chris.persistence.entity"/>
    </bean>
    <!-- 配置掃描器 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.chris.persistence.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

利用Intellij IDEA,能夠看到mapperLocations對應的value呈紅色,由於在resources包下並無mapper文件夾和xml文件。

這個時候應該停下來想一想MyBatis怎麼作到ORM? 整體來講,同Hibernate相似

    1. 數據庫表中的記錄同java bean對應

Record:

Java Bean:

import java.util.Date;

public class Report {
    private Integer id;
    private String name;
    private String description;
    private String owner;
    private String customer;
    private Date created;
    private String createdby;
    private Date updated;
    private String updatedby;
    private Integer version;
    private Integer clientversion;

    public Report(Integer id, String name, String description, String owner, String customer, Date created, String createdby, Date updated, String updatedby, Integer version, Integer clientversion) {
        this.id = id;
        this.name = name;
        this.description = description;
        this.owner = owner;
        this.customer = customer;
        this.created = created;
        this.createdby = createdby;
        this.updated = updated;
        this.updatedby = updatedby;
        this.version = version;
        this.clientversion = clientversion;
    }

    public Report() {
        super();
    }

    setter; getter...

    2. 程序調用接口方法並根據mapper文件執行sql語句

dao層:

import com.chris.persistence.entity.Report;
import com.chris.persistence.entity.SubReport;

import java.util.List;

public interface ReportMapper {
    int deleteByPrimaryKey(Integer id);
    int insert(Report record);
    int insertSelective(Report record);
    Report selectByPrimaryKey(Integer id);
    int updateByPrimaryKeySelective(Report record);
    int updateByPrimaryKey(Report record);
    List<SubReport> selectReportListByPWID(String pwid);

}

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" >
<mapper namespace="com.chris.persistence.dao.ReportMapper">
    <resultMap id="BaseResultMap" type="com.chris.persistence.entity.Report">
        <constructor>
            <idArg column="Id" jdbcType="INTEGER" javaType="java.lang.Integer"/>
            <arg column="Name" jdbcType="VARCHAR" javaType="java.lang.String"/>
            <arg column="Description" jdbcType="VARCHAR" javaType="java.lang.String"/>
            <arg column="Owner" jdbcType="CHAR" javaType="java.lang.String"/>
            <arg column="Customer" jdbcType="VARCHAR" javaType="java.lang.String"/>
            <arg column="Created" jdbcType="TIMESTAMP" javaType="java.util.Date"/>
            <arg column="CreatedBy" jdbcType="VARCHAR" javaType="java.lang.String"/>
            <arg column="Updated" jdbcType="TIMESTAMP" javaType="java.util.Date"/>
            <arg column="UpdatedBy" jdbcType="VARCHAR" javaType="java.lang.String"/>
            <arg column="Version" jdbcType="INTEGER" javaType="java.lang.Integer"/>
            <arg column="ClientVersion" jdbcType="INTEGER" javaType="java.lang.Integer"/>
        </constructor>
    </resultMap>
    <resultMap id="ReportListResultMap" type="SubReport">
        <result column="Id" property="id"/>
        <result column="Name" property="name"/>
        <result column="Description" property="description"/>
    </resultMap>
    <sql id="Base_Column_List">
    Id, Name, Description, Owner, Customer, Created, CreatedBy, Updated, UpdatedBy, Version, 
    ClientVersion
  </sql>
    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer">
        select
        <include refid="Base_Column_List"/>
        from [Report]
        where Id = #{id,jdbcType=INTEGER}
    </select>
    <select id="selectReportListByPWID" parameterType="String" resultMap="ReportListResultMap"> select r.[Id], r.[Name], r.[Description] from [Report] as r left join [Report_Access] as ra on r.[Id]=ra.[ReportId] left join [User] as u on u.[Id]=ra.[UserId] where u.[PWID] = #{pwid} </select>
    <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from [Report]
    where Id = #{id,jdbcType=INTEGER}
  </delete>
    <insert id="insert" parameterType="com.chris.persistence.entity.Report">
    insert into [Report] (Id, Name, Description, 
      Owner, Customer, Created, 
      CreatedBy, Updated, UpdatedBy, 
      Version, ClientVersion)
    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, 
      #{owner,jdbcType=CHAR}, #{customer,jdbcType=VARCHAR}, #{created,jdbcType=TIMESTAMP}, 
      #{createdby,jdbcType=VARCHAR}, #{updated,jdbcType=TIMESTAMP}, #{updatedby,jdbcType=VARCHAR}, 
      #{version,jdbcType=INTEGER}, #{clientversion,jdbcType=INTEGER})
  </insert>
    <insert id="insertSelective" parameterType="com.chris.persistence.entity.Report">
        insert into [Report]
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="id != null">
                Id,
            </if>
            <if test="name != null">
                Name,
            </if>
            <if test="description != null">
                Description,
            </if>
            <if test="owner != null">
                Owner,
            </if>
            <if test="customer != null">
                Customer,
            </if>
            <if test="created != null">
                Created,
            </if>
            <if test="createdby != null">
                CreatedBy,
            </if>
            <if test="updated != null">
                Updated,
            </if>
            <if test="updatedby != null">
                UpdatedBy,
            </if>
            <if test="version != null">
                Version,
            </if>
            <if test="clientversion != null">
                ClientVersion,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">
                #{id,jdbcType=INTEGER},
            </if>
            <if test="name != null">
                #{name,jdbcType=VARCHAR},
            </if>
            <if test="description != null">
                #{description,jdbcType=VARCHAR},
            </if>
            <if test="owner != null">
                #{owner,jdbcType=CHAR},
            </if>
            <if test="customer != null">
                #{customer,jdbcType=VARCHAR},
            </if>
            <if test="created != null">
                #{created,jdbcType=TIMESTAMP},
            </if>
            <if test="createdby != null">
                #{createdby,jdbcType=VARCHAR},
            </if>
            <if test="updated != null">
                #{updated,jdbcType=TIMESTAMP},
            </if>
            <if test="updatedby != null">
                #{updatedby,jdbcType=VARCHAR},
            </if>
            <if test="version != null">
                #{version,jdbcType=INTEGER},
            </if>
            <if test="clientversion != null">
                #{clientversion,jdbcType=INTEGER},
            </if>
        </trim>
    </insert>
    <update id="updateByPrimaryKeySelective" parameterType="com.chris.persistence.entity.Report">
        update [Report]
        <set>
            <if test="name != null">
                Name = #{name,jdbcType=VARCHAR},
            </if>
            <if test="description != null">
                Description = #{description,jdbcType=VARCHAR},
            </if>
            <if test="owner != null">
                Owner = #{owner,jdbcType=CHAR},
            </if>
            <if test="customer != null">
                Customer = #{customer,jdbcType=VARCHAR},
            </if>
            <if test="created != null">
                Created = #{created,jdbcType=TIMESTAMP},
            </if>
            <if test="createdby != null">
                CreatedBy = #{createdby,jdbcType=VARCHAR},
            </if>
            <if test="updated != null">
                Updated = #{updated,jdbcType=TIMESTAMP},
            </if>
            <if test="updatedby != null">
                UpdatedBy = #{updatedby,jdbcType=VARCHAR},
            </if>
            <if test="version != null">
                Version = #{version,jdbcType=INTEGER},
            </if>
            <if test="clientversion != null">
                ClientVersion = #{clientversion,jdbcType=INTEGER},
            </if>
        </set>
        where Id = #{id,jdbcType=INTEGER}
    </update>
    <update id="updateByPrimaryKey" parameterType="com.chris.persistence.entity.Report">
    update [Report]
    set Name = #{name,jdbcType=VARCHAR},
      Description = #{description,jdbcType=VARCHAR},
      Owner = #{owner,jdbcType=CHAR},
      Customer = #{customer,jdbcType=VARCHAR},
      Created = #{created,jdbcType=TIMESTAMP},
      CreatedBy = #{createdby,jdbcType=VARCHAR},
      Updated = #{updated,jdbcType=TIMESTAMP},
      UpdatedBy = #{updatedby,jdbcType=VARCHAR},
      Version = #{version,jdbcType=INTEGER},
      ClientVersion = #{clientversion,jdbcType=INTEGER}
    where Id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

OK, 寫到這裏應該明白MyBatis的最核心部分是mapper.xml。

對接觸MyBatis時間不長的人來講,最快的辦法是有個現成的mapper.xml在那可供參考,而後慢慢熟悉mapper.xml的語法和寫法,而不是詳細的閱讀mapper.xml如何寫。

有個mybatis generator工具,能夠用來幫助生成mapper.xml。

    添加maven依賴:

<dependency>
  <groupId>org.mybatis.generator</groupId>
  <artifactId>mybatis-generator-core</artifactId>
  <version>1.3.5</version>
</dependency>

    添加對應的配置文件generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <properties resource="persistence.properties"/>
    <context id="default" targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <jdbcConnection
                driverClass="${jdbc.driverClassName}"
                connectionURL="${jdbc.url}"
                userId="${jdbc.user}"
                password="${jdbc.password}">
        </jdbcConnection>
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <javaModelGenerator targetPackage="com.chris.persistence.entity"
                            targetProject="src/main/java">
            <property name="enableSubPackages" value="false"/>
            <property name="constructorBased" value="true"/>
            <property name="trimStrings" value="true"/>
            <property name="immutable" value="false"/>
        </javaModelGenerator>
        <sqlMapGenerator targetPackage="mapper"
                         targetProject="src/main/resources">
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>
        <javaClientGenerator targetPackage="com.chris.persistence.dao"
                             targetProject="src/main/java" type="XMLMAPPER">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

        <table tableName="User" domainObjectName="User"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
        <table tableName="Resource" domainObjectName="Resource"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
        <table tableName="Version" domainObjectName="Version"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
        <table tableName="Report" domainObjectName="Report"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
        <table tableName="Report_Access" domainObjectName="Report_Access"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
    </context>
</generatorConfiguration>

     用maven build, mybatis-generator:generate -e

    

    以後生成dao和entity

    

在使用mybatis generator工具時,每次運行mybatis-generator:generate -e,dao和entity會被覆蓋,但mapper.xml則是追加的方式被修改,因此注意在mybatis-generator以前刪除mapper.xml文件。

OK, 總的來講,在使用MyBatis作ORM框架時,dao做爲entity和DB record的橋樑,而關於java bean和database row的mapping信息則經過mapper.xml得到。

在MyBatis中,sql寫在mapper.xml文件中,並且重點在於如何利用好resultMap和動態sql

 

內容總結:

(1) MyBatis配置; (2) MyBatis與Spring整合; (3) Mybatis generator使用

 

Done! 

相關文章
相關標籤/搜索