【Java架構:基礎技術】一篇文章搞掂:MyBatis

 本文篇幅較長,建議合理利用右上角目錄進行查看(若是沒有目錄請刷新)。html

本文主要總結於劉增輝的《MyBatisc從入門到精通》一書,有興趣的朋友能夠自行研讀前端

建議仔細研讀官方文檔:java

http://www.mybatis.org/mybatis-3/zh/mysql

http://www.mybatis.org/spring/zh/git

http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/github

1、MyBatis簡介

什麼是MyBatis:

  • 一個數據持久化框架
  • 支持定製化 SQL、存儲過程以及高級映射
  • 能講Java的POJO映射爲數據庫記錄
  • Mybatis對比其餘持久化框架,優勢在於SQL容易控制,方便優化

MyBatis基本原理:

  • 經過XML文件,根據MyBatis提供的語法,編寫增刪改查的代碼
  • 建立實體和接口,與XML文件映射
  • 系統調用實體和接口進行編程
  • 從而實現了SQL語句到實體和接口的映射

2、MyBatis的基本用法

本例子用RBAC(Role-Based Access Control 基於角色的權限訪問控制)系統做爲例子來介紹MyBatis的XML基本用法:

2.一、先增長几個數據庫表

DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用戶ID', `user_name` varchar(50) DEFAULT NULL COMMENT '用戶名', `user_password` varchar(50) DEFAULT NULL COMMENT '密碼', `user_email` varchar(50) DEFAULT 'test@mybatis.tk' COMMENT '郵箱', `user_info` text COMMENT '簡介', `head_img` blob COMMENT '頭像', `create_time` datetime DEFAULT NULL COMMENT '建立時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1035 DEFAULT CHARSET=utf8 COMMENT='用戶表'; DROP TABLE IF EXISTS `sys_role`; CREATE TABLE `sys_role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID', `role_name` varchar(50) DEFAULT NULL COMMENT '角色名', `enabled` int(11) DEFAULT NULL COMMENT '有效標誌', `create_by` bigint(20) DEFAULT NULL COMMENT '建立人', `create_time` datetime DEFAULT NULL COMMENT '建立時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='角色表'; DROP TABLE IF EXISTS `sys_privilege`; CREATE TABLE `sys_privilege` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '權限ID', `privilege_name` varchar(50) DEFAULT NULL COMMENT '權限名稱', `privilege_url` varchar(200) DEFAULT NULL COMMENT '權限URL', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='權限表'; DROP TABLE IF EXISTS `sys_user_role`; CREATE TABLE `sys_user_role` ( `user_id` bigint(20) DEFAULT NULL COMMENT '用戶ID', `role_id` bigint(20) DEFAULT NULL COMMENT '角色ID' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶角色關聯表'; DROP TABLE IF EXISTS `sys_role_privilege`; CREATE TABLE `sys_role_privilege` ( `role_id` bigint(20) DEFAULT NULL COMMENT '角色ID', `privilege_id` bigint(20) DEFAULT NULL COMMENT '權限ID' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色權限關聯表';
View Code

2.二、插入測試數據

INSERT INTO `sys_privilege` VALUES ('1', '用戶管理', '/users'); INSERT INTO `sys_privilege` VALUES ('2', '角色管理', '/roles'); INSERT INTO `sys_privilege` VALUES ('3', '系統日誌', '/logs'); INSERT INTO `sys_privilege` VALUES ('4', '人員維護', '/persons'); INSERT INTO `sys_privilege` VALUES ('5', '單位維護', '/companies'); INSERT INTO `sys_role` VALUES ('1', '管理員', '1', '1', '2016-04-01 17:02:14'); INSERT INTO `sys_role` VALUES ('2', '普通用戶', '1', '1', '2016-04-01 17:02:34'); INSERT INTO `sys_role_privilege` VALUES ('1', '1'); INSERT INTO `sys_role_privilege` VALUES ('1', '3'); INSERT INTO `sys_role_privilege` VALUES ('1', '2'); INSERT INTO `sys_role_privilege` VALUES ('2', '4'); INSERT INTO `sys_role_privilege` VALUES ('2', '5'); INSERT INTO `sys_user` VALUES ('1', 'admin', '123456', 'admin@mybatis.tk', '管理員用戶', 0x1231231230, '2016-06-07 01:11:12'); INSERT INTO `sys_user` VALUES ('1001', 'test', '123456', 'test@mybatis.tk', '測試用戶', 0x1231231230, '2016-06-07 00:00:00'); INSERT INTO `sys_user_role` VALUES ('1', '1'); INSERT INTO `sys_user_role` VALUES ('1', '2'); INSERT INTO `sys_user_role` VALUES ('1001', '2');
View Code

2.三、建立實體類

開發中建立實體類可使用MyBatis Generator工具來根據數據庫表來生成實體類spring

package tk.mybatis.simple.model; import java.io.Serializable; /** * 權限表 */
public class SysPrivilege implements Serializable { private static final long serialVersionUID = 6315662516417216377L; /** * 權限ID */
    private Long id; /** * 權限名稱 */
    private String privilegeName; /** * 權限URL */
    private String privilegeUrl; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getPrivilegeName() { return privilegeName; } public void setPrivilegeName(String privilegeName) { this.privilegeName = privilegeName; } public String getPrivilegeUrl() { return privilegeUrl; } public void setPrivilegeUrl(String privilegeUrl) { this.privilegeUrl = privilegeUrl; } }
View Code
package tk.mybatis.simple.model; import java.io.Serializable; import java.util.Date; import java.util.List; import tk.mybatis.simple.type.Enabled; /** * 角色表 */
public class SysRole implements Serializable { private static final long serialVersionUID = 6320941908222932112L; /** * 角色ID */
    private Long id; /** * 角色名 */
    private String roleName; /** * 有效標誌 */
    private Enabled enabled; /** * 建立人 */
    private String createBy; /** * 建立時間 */
    private Date createTime; /** * 用戶信息 */
    private SysUser user; /** * 建立信息 */
    private CreateInfo createInfo; public CreateInfo getCreateInfo() { return createInfo; } public void setCreateInfo(CreateInfo createInfo) { this.createInfo = createInfo; } /** * 角色包含的權限列表 */ List<SysPrivilege> privilegeList; public List<SysPrivilege> getPrivilegeList() { return privilegeList; } public void setPrivilegeList(List<SysPrivilege> privilegeList) { this.privilegeList = privilegeList; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public Enabled getEnabled() { return enabled; } public void setEnabled(Enabled enabled) { this.enabled = enabled; } public String getCreateBy() { return createBy; } public void setCreateBy(String createBy) { this.createBy = createBy; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public SysUser getUser() { return user; } public void setUser(SysUser user) { this.user = user; } }
View Code
package tk.mybatis.simple.model; /** * 角色權限關聯表 */
public class SysRolePrivilege { /** * 角色ID */
    private Long roleId; /** * 權限ID */
    private Long privilegeId; public Long getRoleId() { return roleId; } public void setRoleId(Long roleId) { this.roleId = roleId; } public Long getPrivilegeId() { return privilegeId; } public void setPrivilegeId(Long privilegeId) { this.privilegeId = privilegeId; } }
View Code
package tk.mybatis.simple.model; import java.io.Serializable; import java.util.Date; import java.util.List; /** * 用戶表 */
public class SysUser implements Serializable { private static final long serialVersionUID = -328602757171077630L; /** * 用戶ID */
    private Long id; /** * 用戶名 */
    private String userName; /** * 密碼 */
    private String userPassword; /** * 郵箱 */
    private String userEmail; /** * 簡介 */
    private String userInfo; /** * 頭像 */
    private byte[] headImg; /** * 建立時間 */
    private Date createTime; /** * 用戶角色 */
    private SysRole role; /** * 用戶的角色集合 */
    private List<SysRole> roleList; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPassword() { return userPassword; } public void setUserPassword(String userPassword) { this.userPassword = userPassword; } public String getUserEmail() { return userEmail; } public void setUserEmail(String userEmail) { this.userEmail = userEmail; } public String getUserInfo() { return userInfo; } public void setUserInfo(String userInfo) { this.userInfo = userInfo; } public byte[] getHeadImg() { return headImg; } public void setHeadImg(byte[] headImg) { this.headImg = headImg; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public SysRole getRole() { return role; } public void setRole(SysRole role) { this.role = role; } public List<SysRole> getRoleList() { return roleList; } public void setRoleList(List<SysRole> roleList) { this.roleList = roleList; } }
View Code
package tk.mybatis.simple.model; /** * 用戶角色關聯表 */
public class SysUserRole { /** * 用戶ID */
    private Long userId; /** * 角色ID */
    private Long roleId; public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } public Long getRoleId() { return roleId; } public void setRoleId(Long roleId) { this.roleId = roleId; } }
View Code

2.四、建立Mapper.xml和對應接口類

在 src/main/resources 的 tk.mybatis.simple.mapper 目錄下建立 5 個表各自對應的 XML 文件,分別爲 UserMapper.xml 、 RoleMapper.xml 、 PrivilegeMapper.xml 、 UserRoleMapper.xml 和RolePrivilegeMapper.xml 。sql

在 src/main/java下面建立包 tk.mybatis.simple.mapper 。接着,在該包下建立 XML 文件對應的接口類,分別爲 UserMapper.java 、 RoleMapper.java 、 PrivilegeMapper.java 、UserRoleMapper.java 和 RolePrivilegeMapper.java數據庫

下面以User表對應的XML文件和接口類設計爲例介紹如何實現express

UserMapper.java

package tk.mybatis.simple.mapper; public interface UserMapper { }
View Code

UserMapper.xml

此文件用全限定的類名,把接口和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="tk.mybatis.simple.mapper.UserMapper">
    
</mapper>
View Code

2.五、建立MyBatis配置文件

mybatis-config.xml

把UserMapper配置到mybatis裏面去,有2種方法:

一、經過接口配置

<mappers>
    <package name="tk.mybatis.simple.mapper" />
</mappers>
View Code

二、經過xml文件配置

<mappers>
    <mapper resource="tk/mybatis/simple/mapper/UserMapper.xml" />
</mappers>
View Code

建議經過接口配置,由於只須要指定接口所在的包,MyBatis會掃描全部接口對應的Mapper

這種方式的運行流程以下:

  • 一、判斷接口對應的命名空間是否已經存在,若是不存在就拋出異常,存在就繼續進行接下來的操做
  • 二、加載接口對應的XML映射文件,將接口全限定名轉換爲路徑,例如,將接口tk.mybatis.simple.mapper.UserMapper轉換爲tk/mybatis/simple/mapper/UserMapper.xml,以.xml爲後綴搜索XML資源,若是找到就解析XML 
  • 三、處理接口中的註解方法

3、MyBatis的XML語法

3.一、select用法

使用純粹的JDBC時,須要寫查詢語句,而且對結果集進行手動處理,將結果映射到對象的屬性中

使用 MyBatis 時,只須要在XML中添加一個select元素,寫一個SQL,再作一些簡單的配置,就能夠將查詢的結果直接映射到對象中

下面以用id查找用戶爲例,講解select用法:

一、添加對應接口方法selectById

public interface UserMapper { /** * 經過 id 查詢用戶 * * @param id * @return
     */ SysUser selectById(Long id); }
View Code

二、添加對應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="tk.mybatis.simple.mapper.UserMapper">
    <resultMap id="userMap" type="tk.mybatis.simple.model.SysUser">
        <id property="id" column="id" />
        <result property="userName" column="user_name" />
        <result property="userPassword" column="user_password" />
        <result property="userEmail" column="user_email" />
        <result property="userInfo" column="user_info" />
        <result property="headImg" column="head_img" jdbcType="BLOB" />
        <result property="createTime" column="create_time" jdbcType="TIMESTAMP" />
    </resultMap>

    <select id="selectById" resultMap="userMap"> select * from sys_user where id = #{id} </select>
</mapper>
View Code
  • 接口與XML的關聯:經過XML的<mapper>標籤的namespace值設置爲接口的全限定名稱進行關聯
  • 接口中方法與XML的關聯:經過XML的<select>標籤的id值設置爲接口方法名稱進行關聯

三、XML的設計規則

  • a、只使用XML而不使用接口時,namespace的值能夠設置爲任意不重複的值
  • b、標籤的 id 屬性值在任什麼時候候都不能出現英文句號 「.」 ,而且同一個命名空間下不能出現重複的id
  • c、由於接口方法是能夠重載的,因此接口中能夠出現多個同名但參數不一樣的方法,可是 XML 中 id 的值不能重複,於是接口中的全部同名方法會對應着 XML 中的同一個 id 的方法。最多見的用法就是,同名方法中其中一個方法增長一個 RowBound  類型的參數用於實現分頁查詢

四、XML的標籤與屬性

<select>標籤

映射查詢語句使用的標籤

  • id:命名空間中的惟一標識符,可用來表明這條語句
  • resultMap:用於設置返回值的類型和映射關係
  • resultType:直接自動影射爲某對象
  • select * from sys_user where id=#{id} 是查詢語句
  • #{id}:MyBatis SQL中使用預編譯參數的一種方式,大括號中的 id 是傳入的參數名
  • 在上面的select中,使用resultMap設置返回值的類型,這裏的userMap就是上面<resultMap>中的id屬性值,經過id引用須要的<resultMap>

<resultMap>標籤:

用於配置Java對象的屬性和查詢結果列的對應關係,經過resultMap中配置的column和property能夠將查詢列的值映射到type對象的屬性上,所以當咱們使用select*查詢全部列的時候,MyBatis也能夠將結果正確地映射到SysUser對象上

  • id:必填,而且惟一。在select標籤中,resultMap指定的值即爲此處id所設置的值
  • type:必填,用於配置查詢列所映射到的Java對象類型
  • extends:選填,能夠配置當前的resultMap繼承自其餘的resultMap,屬性值爲繼承resultMap的id
  • autoMapping:選填,可選值爲true或false,用因而否啓用非映射字段(沒有在resultMap中的字段)的自動映射功能,該能夠覆蓋全局的autoMappingBehavior

<resultMap>下的標籤:

  • <constructor>標籤:配置使用構造方法注入結果,包含如下兩個子標籤
    • <idArg>標籤:id參數,標記結果做爲id(惟一值),能夠幫助提升總體性能。
    • <arg>標籤:注入到構造方法的一個普通結果。
  • <id>標籤:一個id結果,標記結果做爲id(惟一值),能夠幫助提升總體性能。
  • <result>標籤:注入到Java對象屬性的普通結果。
  • <idArg>、<arg>和<id>、<result>的含義相同,不一樣在於前者是經過類的構造函數注入,後者是經過屬性的setter方法注入
  • <association>標籤:一個複雜的類型關聯,許多結果將包成這種類型。
  • <collection>標籤:複雜類型的集合。
  • <discriminator>標籤:根據結果值來決定使用哪一個結果映射。
  • <case>標籤:基於某些值的結果映射。

<id>和<result>裏面的屬性:

  • column:從數據庫中獲得的列名,或者是列的別名。
  • property:映射到列結果的屬性。能夠映射簡單的如「username」這樣的屬性,也能夠映射一些複雜對象中的屬性,例如「address.street.number」,這會經過「.」方式的屬性嵌套賦值。
  • javaType:一個Java類的徹底限定名,或一個類型別名(經過typeAlias配置或者默認的類型)。若是映射到一個JavaBean,MyBatis一般能夠自動判斷屬性的類型。若是映射到HashMap,則須要明確地指定javaType屬性。
  • jdbcType:列對應的數據庫類型。JDBC類型僅僅須要對插入、更新、刪除操做可能爲空的列進行處理。這是JDBCjdbcType的須要,而不是MyBatis的須要。
  • typeHandler:使用這個屬性能夠覆蓋默認的類型處理器。這個屬性值是類的徹底限定名或類型別名

如何定義返回值

  • resultMap:用resultMap來設置映射
  • resultType:根據讀取結果和對應類自動映射,能夠在select中使用別名,來和類的屬性名對應

五、多結果查詢例子

接口方法

/** * 查詢所有用戶 * * @return
     */ List<SysUser> selectAll();
View Code

XML設置

<select id="selectAll" resultType="tk.mybatis.simple.model.SysUser"> select id, user_name userName, user_password userPassword, user_email userEmail, user_info userInfo, head_img headImg, create_time createTime from sys_user </select>
View Code

這個例子中,select標籤中直接使用resultType,以及使用字段別名,使sql的字段名與類的字段名對上,便可自動映射

六、名稱映射規則

綜上,有2種方式:一、在resultMap中配置property屬性和column屬性的映射;二、SQL中設置別名

property或者別名要與對象的屬性名對應才能匹配,實際匹配時,是把字母都轉換成大寫來匹配的,因此不區分大小寫;通常爲了閱讀,應該統一寫法就OK

一種很常見的狀況,數據庫使用下劃線命名方式,如user_Name;而Java中使用駝峯式命名,如userName

MyBatis提供了一個配置,自動將這2種方式進行匹配,在配置文件中設置便可,代碼以下

<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
View Code

七、添加單元測試代碼

在src/test/java下的tk.mybatis.simple.mapper包中,添加基礎測試類

package tk.mybatis.simple.mapper; import java.io.IOException; import java.io.Reader; 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.BeforeClass; /** * 基礎測試類 */
public class BaseMapperTest { private static SqlSessionFactory sqlSessionFactory; @BeforeClass public static void init(){ try { Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); } catch (IOException ignore) { ignore.printStackTrace(); } } public SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
View Code

修改CountryMapperTest類

由於Country和User的Mapper中都有SelectAll,因此不在惟一,須要用全限定類名tk.mybatis.simple.mapper.CountryMapper.selectAll去調用

package tk.mybatis.simple.mapper; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import tk.mybatis.simple.model.Country; public class CountryMapperTest extends BaseMapperTest { @Test public void testSelectAll() { SqlSession sqlSession = getSqlSession(); try { List<Country> countryList = sqlSession.selectList("tk.mybatis.simple.mapper.CountryMapper.selectAll"); printCountryList(countryList); } finally { sqlSession.close(); } } private void printCountryList(List<Country> countryList) { for (Country country : countryList) { System.out.printf("%-4d%4s%4s\n", country.getId(), country.getCountryname(), country.getCountrycode()); } } }
View Code

 修改mybatis-config.xml,把CountryMapper.xml加入到Mapper配置中

<mappers>
    <mapper resource="tk/mybatis/simple/mapper/CountryMapper.xml" />
    <package name="tk.mybatis.simple.mapper" />
</mappers>
View Code

完成上面設置後便可進行單元測試

八、一些複雜用法

a、關聯查找某個表的數據

接口方法

/** * 根據用戶 id 獲取角色信息 * * @param userId * @return
 */ List<SysRole> selectRolesByUserId(Long userId);
View Code

XML配置

<select id="selectRolesByUserId" resultType="tk.mybatis.simple.model.SysRole"> select r.id, r.role_name roleName, r.enabled, r.create_by createBy, r.create_time createTime, u.user_name as "user.userName", u.user_email as "user.userEmail" from sys_user u inner join sys_user_role ur on u.id = ur.user_id inner join sys_role r on ur.role_id = r.id where u.id = #{userId} </select>
View Code

由於使用了自定義類型Enable,因此在mybatis-config.xml加入自定義類型處理器

<typeHandlers>
    <typeHandler javaType="tk.mybatis.simple.type.Enabled" handler="tk.mybatis.simple.type.EnabledTypeHandler"/>
</typeHandlers>
View Code

這種狀況,雖然有關聯表查詢,可是隻是一個實體的數據,因此只是sql中加入了join語句的不一樣,其它和單個表查詢基本相同

b、關聯查詢多個表數據

例如a中,我不只要查詢角色,也要帶上用戶的信息,那就是要查詢出2個表的信息了,那麼能夠以下這麼作

第一種:把用戶的信息增長到角色表中;不過這種方式不建議

package tk.mybatis.simple.model; public class SysRoleExtend extends SysRole { private String userName; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
View Code

第二種:把user表加到角色表中

public class SysRole implements Serializable { /** * 用戶信息 */
    private SysUser user; ......
View Code

修改mapper,使用「.」的方式增長user須要的信息

<select id="selectRolesByUserId" resultType="tk.mybatis.simple.model.SysRole"> select r.id, r.role_name roleName, r.enabled, r.create_by createBy, r.create_time createTime, u.user_name as "user.userName", u.user_email as "user.userEmail" from sys_user u inner join sys_user_role ur on u.id = ur.user_id inner join sys_role r on ur.role_id = r.id where u.id = #{userId} </select>
View Code

測試代碼

 @Test public void testSelectRolesByUserId(){ SqlSession sqlSession = getSqlSession(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //調用 selectRolesByUserId 方法查詢用戶的角色
            List<SysRole> roleList = userMapper.selectRolesByUserId(1L); //結果不爲空
 Assert.assertNotNull(roleList); //角色數量大於 0 個
            Assert.assertTrue(roleList.size() > 0); } finally { //不要忘記關閉 sqlSession
 sqlSession.close(); } }
View Code

2.三、MyBatis的XML基本用法——insert用法

insert比較簡單,除了須要返回主鍵時,不一樣數據庫的方式有所不一樣

一、簡單用法

添加接口方法

/** * 新增用戶 * * @param sysUser * @return
 */
int insert(SysUser sysUser);
View Code

 添加XML設置

<insert id="insert"> insert into sys_user( user_name, user_password, user_email, user_info, head_img, create_time) values( #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP}) </insert>
View Code

測試代碼

@Test public void testInsert() { SqlSession sqlSession = getSqlSession(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 建立一個 user 對象
        SysUser user = new SysUser(); user.setUserName("test1"); user.setUserPassword("123456"); user.setUserEmail("test@mybatis.tk"); user.setUserInfo("test info"); // 正常狀況下應該讀入一張圖片存到 byte 數組中
        user.setHeadImg(new byte[] { 1, 2, 3 }); user.setCreateTime(new Date()); // 將新建的對象插入數據庫中,特別注意,這裏的返回值 result 是執行的 SQL 影響的行數
        int result = userMapper.insert(user); // 只插入 1 條數據
        Assert.assertEquals(1, result); // id 爲 null,咱們沒有給 id 賦值,而且沒有配置回寫 id 的值
 Assert.assertNull(user.getId()); } finally { // 爲了避免影響數據庫中的數據致使其餘測試失敗,這裏選擇回滾 // 因爲默認的 sqlSessionFactory.openSession() 是不自動提交的, // 所以不手動執行 commit 也不會提交到數據庫
 sqlSession.rollback(); // 不要忘記關閉 sqlSession
 sqlSession.close(); } }
View Code

<insert>標籤包含以下屬性:

  • id:命名空間中的惟一標識符,可用來表明這條語句。
  • parameterType:即將傳入的語句參數的徹底限定類名或別名。這個屬性是可選的,由於MyBatis能夠推斷出傳入語句的具體參數,所以不建議配置該屬性。
  • flushCache:默認值爲true,任什麼時候候只要語句被調用,都會清空一級緩存和二級緩存。
  • timeout:設置在拋出異常以前,驅動程序等待數據庫返回請求結果的秒數。
  • statementType:對於STATEMENT、PREPARED、CALLABLE,MyBatis會分別使用對應的Statement、PreparedStatement、CallableStatement,默認值爲PREPARED。
  • useGeneratedKeys:默認值爲false。若是設置爲true,MyBatis會使用JDBC的getGeneratedKeys方法來取出由數據庫內部生成的主鍵。
  • keyProperty:MyBatis經過getGeneratedKeys獲取主鍵值後將要賦值的屬性名。若是但願獲得多個數據庫自動生成的列,屬性值也能夠是以逗號分隔的屬性名稱列表。
  • keyColumn:僅對INSERT和UPDATE有用。經過生成的鍵值設置表中的列名,這個設置僅在某些數據庫(如PostgreSQL)中是必須的,當主鍵列不是表中的第一列時須要設置。若是但願獲得多個生成的列,也能夠是逗號分隔的屬性名稱列表。
  • databaseId:若是配置了databaseIdProvider(4.6節有詳細配置方法),MyBatis會加載全部的不帶databaseId的或匹配當前databaseId的語句。若是同時存在帶databaseId和不帶databaseId的語句,後者會被忽略。
  • 此處<insert>中的SQL就是一個簡單的INSERT語句,將全部的列都列舉出來,在values中經過#{property}方式從參數中取出屬性的值。
  • 爲了防止類型錯誤,對於一些特殊的數據類型,建議指定具體的jdbcType值。例如headImg指定BLOB類型,createTime指定TIMESTAMP類型。
  • 特別說明!
  • BLOB對應的類型是ByteArrayInputStream,就是二進制數據流。
  • 因爲數據庫區分date、time、datetime類型,可是Java中通常都使用java.util.Date類型。所以爲了保證數據類型的正確,須要手動指定日期類型,date、time、datetime對應的JDBC類型分別爲DATE、TIME、TIMESTAMP。

二、使用JDBC方式返回主鍵自增的值

適用於數據庫自己能夠設置字段爲自增的狀況

接口方法

/** * 新增用戶 - 使用 useGeneratedKeys 方式 * * @param sysUser * @return
 */
int insert2(SysUser sysUser);
View Code

XML配置,主要和上面例子增長了useGeneratedKeys="true" keyProperty="id"

<insert id="insert2" useGeneratedKeys="true" keyProperty="id"> insert into sys_user( user_name, user_password, user_email, user_info, head_img, create_time) values( #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP}) </insert>
View Code

useGeneratedKeys設置爲true後,MyBatis會使用JDBC的getGeneratedKeys方法來取出由數據庫內部生成的主鍵。得到主鍵值後將其賦值給keyProperty配置的id屬性。當須要設置多個屬性時,使用逗號隔開,這種狀況下一般還須要設置keyColumn屬性,按順序指定數據庫的列,這裏列的值會和keyProperty配置的屬性一一對應

測試代碼

@Test public void testInsert2() { SqlSession sqlSession = getSqlSession(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 建立一個 user 對象
        SysUser user = new SysUser(); user.setUserName("test1"); user.setUserPassword("123456"); user.setUserEmail("test@mybatis.tk"); user.setUserInfo("test info"); user.setHeadImg(new byte[] { 1, 2, 3 }); user.setCreateTime(new Date()); int result = userMapper.insert2(user); // 只插入 1 條數據
        Assert.assertEquals(1, result); // 由於 id 回寫,因此 id 不爲 null
 Assert.assertNotNull(user.getId()); } finally { sqlSession.commit(); // 不要忘記關閉 sqlSession
 sqlSession.close(); } }
View Code

三、使用selectKey返回主鍵的值

這種方式既適用於2的狀況,更適用於數據庫不支持自增列,而是經過序列獲得一個值,而後賦值給id再插入數據庫的狀況

接口方法

/** * 新增用戶 - 使用 selectKey 方式 * * @param sysUser * @return
 */
int insert3(SysUser sysUser);
View Code

XML配置

MySQL數據庫

<insert id="insert3"> insert into sys_user( user_name, user_password, user_email, user_info, head_img, create_time) values( #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP}) <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER"> SELECT LAST_INSERT_ID() </selectKey>
</insert>
View Code

Oracle數據庫

<!-- Oracle 的例子,查詢多個列的時候須要 keyColumn -->
<insert id="insertOracle">
    <selectKey keyColumn="id" resultType="long" keyProperty="id" order="BEFORE"> SELECT SEQ_USER.nextval from dual </selectKey> insert into sys_user( id, user_name, user_password, user_email, user_info, head_img, create_time) values( #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP}) </insert>
View Code

selectKey標籤的keyColumn、keyProperty和上面useGeneratedKeys的用法含義相同,這裏的resultType用於設置返回值類型。order屬性的設置和使用的數據庫有關。在MySQL數據庫中,order屬性設置的值是AFTER,由於當前記錄的主鍵值在insert語句執行成功後才能獲取到。而在Oracle數據庫中,order的值要設置爲BEFORE,這是由於Oracle中須要先從序列獲取值,而後將值做爲主鍵插入到數據庫中

Oracle方式的INSERT語句中明確寫出了id列和值#{id},由於執行selectKey中的語句後id就有值了,咱們須要把這個序列值做爲主鍵值插入到數據庫中,因此必須指定id列,若是不指定這一列,數據庫就會由於主鍵不能爲空而拋出異常

而selectKey標籤的寫法在先後並沒有所謂,影響執行順序的只是order

不一樣數據庫生成id的語句不一樣

  • DB2使用VALUESIDENTITY_VAL_LOCAL()。
  • MYSQL使用SELECTLAST_INSERT_ID()。
  • SQLSERVER使用SELECTSCOPE_IDENTITY()。
  • CLOUDSCAPE使用VALUESIDENTITY_VAL_LOCAL()。
  • DERBY使用VALUESIDENTITY_VAL_LOCAL()。
  • HSQLDB使用CALLIDENTITY()。
  • SYBASE使用SELECT@@IDENTITY。
  • DB2_MF使用SELECTIDENTITY_VAL_LOCAL()FROMSYSIBM.SYSDUMMY1。
  • INFORMIX使用selectdbinfo('sqlca.sqlerrd1')fromsystableswheretabid=1

2.四、MyBatis的XML基本用法——update用法

一、簡單用法

接口方法

/** * 根據主鍵更新 * * @param sysUser * @return
 */
int updateById(SysUser sysUser);
View Code

XML配置

<update id="updateById"> update sys_user set user_name = #{userName}, user_password = #{userPassword}, user_email = #{userEmail}, user_info = #{userInfo}, head_img = #{headImg, jdbcType=BLOB}, create_time = #{createTime, jdbcType=TIMESTAMP} where id = #{id} </update>
View Code

測試代碼

@Test public void testUpdateById() { SqlSession sqlSession = getSqlSession(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 從數據庫查詢 1 個 user 對象
        SysUser user = userMapper.selectById(1L); // 當前 userName 爲 admin
        Assert.assertEquals("admin", user.getUserName()); // 修改用戶名
        user.setUserName("admin_test"); // 修改郵箱
        user.setUserEmail("test@mybatis.tk"); // 更新數據,特別注意,這裏的返回值 result 是執行的 SQL 影響的行數
        int result = userMapper.updateById(user); // 只更新 1 條數據
        Assert.assertEquals(1, result); // 根據當前 id 查詢修改後的數據
        user = userMapper.selectById(1L); // 修改後的名字 admin_test
        Assert.assertEquals("admin_test", user.getUserName()); } finally { // 爲了避免影響數據庫中的數據致使其餘測試失敗,這裏選擇回滾 // 因爲默認的 sqlSessionFactory.openSession() 是不自動提交的, // 所以不手動執行 commit 也不會提交到數據庫
 sqlSession.rollback(); // 不要忘記關閉 sqlSession
 sqlSession.close(); } }
View Code

update就介紹到這裏,更復雜的就須要瞭解後面的動態sql用法了

2.五、MyBatis的XML基本用法——delete用法

一、簡單用法

接口方法

/** * 經過主鍵刪除 * * @param id * @return
 */
int deleteById(Long id); /** * 經過主鍵刪除 * * @param id * @return
 */
int deleteById(SysUser sysUser);
View Code

XML配置

<delete id="deleteById"> delete from sys_user where id = #{id} </delete>
View Code

測試代碼

@Test public void testDeleteById() { SqlSession sqlSession = getSqlSession(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 從數據庫查詢 1 個 user 對象,根據 id = 1 查詢
        SysUser user1 = userMapper.selectById(1L); // 如今還能查詢出 user 對象
 Assert.assertNotNull(user1); // 調用方法刪除
        Assert.assertEquals(1, userMapper.deleteById(1L)); // 再次查詢,這時應該沒有值,爲 null
        Assert.assertNull(userMapper.selectById(1L)); // 使用 SysUser 參數再作一遍測試,根據 id = 1001 查詢
        SysUser user2 = userMapper.selectById(1001L); // 如今還能查詢出 user 對象
 Assert.assertNotNull(user2); // 調用方法刪除,注意這裏使用參數爲 user2
        Assert.assertEquals(1, userMapper.deleteById(user2)); // 再次查詢,這時應該沒有值,爲 null
        Assert.assertNull(userMapper.selectById(1001L)); // 使用 SysUser 參數再作一遍測試
    } finally { // 爲了避免影響數據庫中的數據致使其餘測試失敗,這裏選擇回滾 // 因爲默認的 sqlSessionFactory.openSession() 是不自動提交的, // 所以不手動執行 commit 也不會提交到數據庫
 sqlSession.rollback(); // 不要忘記關閉 sqlSession
 sqlSession.close(); } }
View Code

delete用法也只講到這裏,更復雜的可學習動態sql

2.六、多個接口參數的用法

在前面的例子,全部接口方法都只有一個參數,好比一個string類型的id,或者是一個JavaBean如SysUser

當要傳輸多個參數的時候,有2種好用的方法:一、使用Map類型做爲參數;二、使用@Param註解

使用Map類型做爲參數的方法,就是在Map中經過key來映射XML中SQL使用的參數值名字,value用來存放參數值,須要多個參數時,經過Map的key-value方式傳遞參數值,因爲這種方式還須要本身手動建立Map以及對參數進行賦值,其實並不簡潔,因此對這種方式只作以上簡單介紹,接下來着重講解使用@Param註解的方式

一、一個錯誤的例子

接口方法

/** * 根據用戶 id 和 角色的 enabled 狀態獲取用戶的角色 * * @param userId * @param enabled * @return
 */ List<SysRole> selectRolesByUserIdAndRoleEnabled(Long userId, Integer enabled);
View Code

XML配置

<select id="selectRolesByUserIdAndRoleEnabled" resultType="tk.mybatis.simple.model.SysRole"> select r.id, r.role_name roleName, r.enabled, r.create_by createBy, r.create_time createTime from sys_user u inner join sys_user_role ur on u.id = ur.user_id inner join sys_role r on ur.role_id = r.id where u.id = #{userId} and r.enabled = #{enabled} </select>
View Code

測試代碼

@Test public void testSelectRolesByUserIdAndRoleEnabled() { SqlSession sqlSession = getSqlSession(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 調用 selectRolesByUserIdAndRoleEnabled 方法查詢用戶的角色
        List<SysRole> roleList = userMapper.selectRolesByUserIdAndRoleEnabled(1L, null); // 結果不爲空
 Assert.assertNotNull(roleList); // 角色數量大於 0 個
        Assert.assertTrue(roleList.size() > 0); } finally { // 不要忘記關閉 sqlSession
 sqlSession.close(); } }
View Code

會報錯Parameter 'userId' not found. Available parameters are [0, 1, param1, param2]

這個錯誤表示,XML可用的參數只有0、一、param一、param2,沒有userId。0和1,param1和param2都是MyBatis根據參數位置自定義的名字,這時若是將XML中的#{userId}改成#{0}或#{param1},將#{enabled}改成#{1}或#{param2},這個方法就能夠被正常調用了。這樣講只是爲了讓你們理解它們之間的關係,但實際上並不建議這麼作

二、使用@Param註解

修改接口方法便可

/** * 根據用戶 id 和 角色的 enabled 狀態獲取用戶的角色 * * @param userId * @param enabled * @return
 */ List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("userId") Long userId, @Param("enabled") Integer enabled);
View Code

修改後能夠經過測試

這時的XML文件中對應的SQL的可用參數變成了[userId,enabled,param1,param2],若是把#{userId}改成#{param1},把#{enabled}改成#{param2},測試也能夠經過

給參數配置@Param註解後,MyBatis就會自動將參數封裝成Map類型,@Param註解值會做爲Map中的key,所以在SQL部分就能夠經過配置的註解值來使用參數。

到這裏你們可能會有一個疑問:當只有一個參數(基本類型或擁有TypeHandler配置的類型)的時候,爲何能夠不使用註解?這是由於在這種狀況下(除集合和數組外),MyBatis不關心這個參數叫什麼名字就會直接把這個惟一的參數值拿來使用。

當參數是JavaBean的時候,如

/** * 根據用戶 id 和 角色的 enabled 狀態獲取用戶的角色 * * @param user * @param role * @return
 */ List<SysRole> selectRolesByUserAndRole(@Param("user")SysUser user, @Param("role")SysRole role);
View Code

這時,在XML中就不能直接使用#{userId}和#{enabled}了,而是要經過點取值方式使用#{user.id}和#{role.enabled}從兩個JavaBean中取出指定屬性的值。修改好對應的XML文件後,你們能夠自行完善代碼並進行測試。
除了以上經常使用的參數類型外,接口的參數還多是集合或者數組,這種類型的參數暫不討論

4、動態SQL

使用ORM的人都知道,根據不一樣條件拼裝SQL時會遇到不少麻煩,例如缺乏空格、去掉最後列名的逗號等問題

MyBatis採用 OGNL(Object-Graph Navigation Language)表達式實現動態SQL,更加簡便

4.一、if標籤

根據標籤中的test表達式(下面會詳細講解),若是符合表達式,則拼接在語句中;不然忽略

用於Where條件

<select id="selectTestIf" parameterType="com.LTSolution.ShopApp.Model.Product" resultMap="BaseResultMap"> select * from Product where 1=1 <if test="name != null and name != ''"> and Name like '%'+#{name}+'%' </if>
    <if test="code != null and code != ''"> and Code like '%'+#{code}+'%' </if> order by code </select>

注意:where 1=1 :當2個條件都沒有時,若是不加1=1,會產生語句「select * from Product where」,是一個錯誤語句;可使用Where標籤解決(下面會講解)

用於Update更新

<update id="updateTestIf"> update Product set <if test="name != null and name != ''"> Name = #{name}, </if>
    <if test="brand != null and brand != ''"> Brand = #{brand}, </if> Code = #{code} where Code = #{code} </update>

注意:賦值Code = #{code},也是爲了防止拼裝出來的語句有誤;可使用Where標籤或者Set標籤解決(下面會講解)

用於Insert插入

動態插入,若是實體的值爲空,則不插入,這樣可讓字段的值使用數據庫的默認值,而不是實體中帶的空值。

<update id="insertTestIf" parameterType="com.LTSolution.ShopApp.Model.Product"> insert into Product( Code,TypeId, <if test="brand != null and brand != ''"> Brand, </if> Name) values( #{code},#{typeid}, <if test="brand != null and brand != ''"> #{brand}, </if> #{name} ) </update>

 注意,字段和數值都必須有對應的if,不然會報致使數值數量和字段數量不一致

4.二、choose標籤

 此標籤提供了相似if...else...的功能;在此標籤中必須至少包含一個when,0或1個otherwise

<select id="selectTestChoose" resultMap="BaseResultMap"> select * from Product where 1=1 <choose>
    <when test="code != null and code != ''"> and Code = #{code} </when>
    <when test="name != null and name != ''"> and Name = #{name} </when>
    <otherwise> and 1=2 </otherwise>
    </choose> order by code </select>

若是有編號,按編號查找;沒有編號,按名稱查找;都沒有則查不到。

4.三、where、set 、 trim標籤

他們都用來解決相似拼裝時是否去掉第一個and,是否去掉最後一個逗號等問題

where標籤

where 標籤的做用:若標籤中有內容,則自動插入一個where,不然不插入任何語句 ;若是 where 後面的字符串是以 AND 和 OR 開頭的,就將它們剔除。

修改上面if標籤中where例子,便可省掉where 1=1這個語句

<select id="selectTestIf" parameterType="com.LTSolution.ShopApp.Model.Product" resultMap="BaseResultMap"> select * from Product <where>
        <if test="name != null and name != ''"> and Name like '%'+#{name}+'%' </if>
        <if test="code != null and code != ''"> and Code = #{code} </if>
    </where> order by code </select>

set標籤

set標籤的做用:若標籤中有內容,則自動插入一個set ;若是 set 後面的字符串是以逗號結尾的,就將這個逗號剔除。

修改上面if標籤中update例子以下

<update id="updateTestIf"> update Product <set>
        <if test="name != null and name != ''"> Name = #{name}, </if>
        <if test="brand != null and brand != ''"> Brand = #{brand}, </if> Code = #{code}, </set> where Code = #{code} </update>

trim標籤

where和set標籤的功能均可以用trim標籤來實現,而且在底層就是經過TrimSqlNode實現的

  • 用trim標籤實現where和set

<select id="selectTestIf" parameterType="com.LTSolution.ShopApp.Model.Product" resultMap="BaseResultMap"> select * from Product <trim prefix="WHERE" prefixOverrides="AND |OR ">
        <if test="name != null and name != ''"> and Name like '%'+#{name}+'%' </if>
        <if test="code != null and code != ''"> and Code = #{code} </if>
    </trim> order by code </select>

這裏的AND和OR後面的空格不能省略,爲了不匹配到andes、orders等單詞。

實際的prefixeOverrides包含「AND」、「OR」、「AND\n」、「OR\n」、「AND\r」、「OR\r」、「AND\t」、「OR\t」,不只僅是上面提到的兩個帶空格的前綴。

<update id="updateTestIf"> update Product <trim prefix="SET" suffixOverrides=",">
        <if test="name != null and name != ''"> Name = #{name}, </if>
        <if test="brand != null and brand != ''"> Brand = #{brand}, </if> Code = #{code}, </trim> where Code = #{code} </update>
  • trim標籤有以下屬性
    • prefix:當trim元素內包含內容時,會給內容增長prefix指定的前綴。
    • prefixOverrides:當trim元素內包含內容時,會把內容中匹配的前綴字符串去掉。
    • suffix:當trim元素內包含內容時,會給內容增長suffix指定的後綴。
    • suffixOverrides:當trim元素內包含內容時,會把內容中匹配的後綴字符串去掉。

4.四、foreach標籤

SQL語句中有時會使用IN關鍵字,例如id in(1,2,3)。使用${ids}方式直接獲取值的寫法不能防止SQL注入;使用#{}加上foreach標籤的寫法,能夠避免SQL注入。

foreach能夠對數組、Map或實現了Iterable接口(如List、Set)的對象進行遍歷。

數組在處理時會轉換爲List對象,所以foreach遍歷的對象能夠分爲兩大類:Iterable類型和Map類型。

  • foreach包含如下屬性:
    • collection:必填,值爲要迭代循環的屬性名。這個屬性值的狀況有不少(下面講解)。
    • item:變量名,值爲從迭代對象中取出的每個值。
    • index:索引的屬性名,在集合數組狀況下值爲當前索引值,當迭代循環的對象是Map類型時,這個值爲Map的key(鍵值)。
    • open:整個循環內容開頭的字符串。
    • close:整個循環內容結尾的字符串。
    • separator:每次循環的分隔符。

這兩種類型在遍歷循環時狀況不同,例子以下:

實現in集合或數組

例子:使用傳入的編號集合查找對應商品

//接口
List<Product> selectTestForeach(List<String> idList);
<select id="selectTestForeach" resultMap="BaseResultMap"> select * from Product where code in <foreach collection="list" open="(" close=")" separator="," item="id" index="i"> #{id} </foreach> order by code </select>
  •  collection的設置:

  • 一、只有一個數組參數或者集合參數
    • 參數會先轉換成Map類型,再進行處理
    • 參數爲集合時,轉換成Map中一個key爲colletion的值,此時寫colletion="collection"
    • 參數爲List時,在上面基礎上再添加一個key爲list的值,此時寫colletion="collection"或colletion="list"
    • 參數爲數組時,不一樣於上面2種狀況,會轉換成Map中一個key爲array的值,此時寫colletion="array"
    • 可是推薦使用@Param來指定參數的名稱,這樣就能夠寫colletion="參數名"
  • 二、多個參數
    • 使用@param來命名,寫colletion="參數名"
  • 三、參數是Map類型
    • 將collection指定爲Map中的key
    • 若要循環Map,可使用@Param,而後colletion="參數名";或直接使用colletion="_parameter"
  • 四、參數是一個對象
    • colletion="對象屬性名"
    • 若對象多層嵌套,可使用屬性 . 屬性(集合和數組可使用下標取值)的方式,做爲collection的值

批量插入

若是數據庫支持批量插入,就能夠經過foreach來實現。批量插入是SQL-92新增的特性,目前支持的數據庫有DB二、SQLServer2008及以上版本、PostgreSQL8.2及以上版本、MySQL、SQLite3.7.11及以上版本、H2。

sql語法:insert into table1 (c1,c2,c3..) values (v1,v2,v3..),(v1,v2,v3..),(v1,v2,v3..)

<update id="insertTestForeach"> insert into Product(Code,TypeId,Name) values <foreach collection="list" item="product" separator=","> (#{product.code},#{product.typeid},#{product.name}) </foreach>
</update>

經過item指定了循環變量名後,在引用值的時候使用的是「屬性.屬性」的方式,如product.code

批量插入還能夠返回自增主鍵id,這裏不介紹

動態update

介紹當參數類型是Map的時候,如何用foreach進行動態update

// 接口
int updateTestForeach(Map<String, Object> map);
<update id="updateTestForeach"> update Product set <foreach collection="_parameter" item="val" index="key" separator=","> ${key} = #{val} </foreach> where Code = #{code} </update>

4.五、bind標籤

bind標籤可使用OGNL表達式建立一個變量並綁定到上下文中

例如鏈接函數concat,不一樣數據庫用法不一樣,能夠改爲用bind標籤的OGNL來表示,便可消除不一樣數據庫不一樣寫法的影響,並且能夠防止sql注入

bind標籤有2個屬性,name爲給上下文引用的變量名,value爲OGNL表達式

<select id="selectTestIf" parameterType="com.LTSolution.ShopApp.Model.Product" resultMap="BaseResultMap"> select * from Product <where>
        <if test="name != null and name != ''">
            <bind name="nameLike" value="'%'+name+'%'" /> and Name like #{nameLike} </if>
    </where> order by code </select>

4.六、多數據庫支持

使用if標籤以及由MyBatis提供的databaseIdProvider數據庫廠商標識配置

MyBatis根據映射語句中的databaseId屬性,對不一樣的數據庫執行對應的語句;MyBatis會加載不帶databaseId屬性以及匹配當前數據庫databaseId屬性的語句;若是同時找到同id,不帶databaseId屬性和帶databaseId屬性的語句,不帶databaseId屬性的語句會被捨棄掉。

設置

首先,須要在mybatis-config.xml文件中加入配置

<databaseIdProvider type="DB_VENDOR"/>

在這個設置下,系統經過DatabaseMetaData#getDatabaseProductName()方法獲取數據庫名稱,可是根據不一樣數據庫版本,返回的名稱會不一樣,比較難管理,因此有如下方式

<databaseIdProvider type="DB_VENDOR">
  <property name="SQL Server" value="sqlserver"/>    
  <property name="DB2" value="db2"/>    
  <property name="Oracle" value="oracle" />
  <property name="MySQL" value="mysql"/>  
  <property name="PostgreSQL" value="postgresql"/>    
  <property name="Derby" value="derby"/>    
  <property name="HSQL" value="hsqldb"/>    
  <property name="H2" value="h2"/>           
</databaseIdProvider>

經過配置,只要DatabaseMetaData#getDatabaseProductName()的返回值部分字符匹配某個屬性的name,就會返回對應的value值

注意!Spring Boot中不可使用使用配置文件的形式,應該添加一個Bean

package com.LTSolution.ShopApp; import java.util.Properties; import org.apache.ibatis.mapping.DatabaseIdProvider; import org.apache.ibatis.mapping.VendorDatabaseIdProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyBatisBean { @Bean public DatabaseIdProvider getDatabaseIdProvider() { DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider(); Properties properties = new Properties(); properties.setProperty("Oracle", "oracle"); properties.setProperty("MySQL", "mysql"); properties.setProperty("DB2", "db2"); properties.setProperty("Derby", "derby"); properties.setProperty("H2", "h2"); properties.setProperty("HSQL", "hsql"); properties.setProperty("Informix", "informix"); properties.setProperty("SQL Server", "sqlserver"); properties.setProperty("PostgreSQL", "postgresql"); properties.setProperty("Sybase", "sybase"); properties.setProperty("Hana", "hana"); databaseIdProvider.setProperties(properties); return databaseIdProvider; } }

 修改語句

方式1:對select,insert,delete,update,selectKey,sql標籤,設置databaseId屬性。MyBatis會根據數據庫執行對應的語句

<select id="selectTestIf" databaseId="mysql"> .... </select>
<select id="selectTestIf" databaseId="sqlserver"> .... </select>

 方式2:使用_databaseId參數。爲了不大量重複的SQL,可使用_databaseId參數進行對不一樣的部分進行判斷。

<select id="selectTestIf" parameterType="com.LTSolution.ShopApp.Model.Product" resultMap="BaseResultMap"> select * from Product <where>
        <if test="name != null and name != ''">
            <if test="_databaseId == 'mysql'"> and Name like concat('%'+#{name}+'%') </if>
            <if test="_databaseId == 'sqlserver'"> and Name like '%'+#{name}+'%' </if>
        </if>
    </where> order by code </select>

4.七、OGNL用法

在MyBatis的動態SQL和${}形式的參數中都用到了OGNL表達式。MyBatis經常使用的OGNL表達式以下:

1.e1 or e2 2.e1 and e2 3.e1==e2或e1 eq e2 4.e1 !=e2或e1 neq e2 5.e1 lt e2:小於 6.e1 lte e2:小於等於,其餘表示爲gt(大於)、gte(大於等於) 7.e1+e二、e1*e二、e1/e二、e1-e二、e1%e2 8.!e或not e:非,取反 9.e.method( args ):=調用對象方法 10.e.property:對象屬性值 11.e1[e2]:按索引取值( List、數組和Map) 12.@class@method(args):調用類的靜態方法 13.@class@field:調用類的靜態字段值

5、Mybatis插件開發——攔截器(未整理)

MyBatis容許在已映射語句執行過程當中的某一點進行攔截調用。默認狀況下,MyBatis能夠攔截一下4個接口中的幾個方法(括號內爲該接口的方法名)。

  • Executor(update、query、flushStatements、commit、rollback、getTransaction、close、isClosed)
  • ParameterHandler(getParameterObject、setParameters)
  • ResultSetHandler(handleResultSets、handleCursorResultSets、handleOutputParameters)
  • StatementHandler(prepare、parameterize、batch、update、query)

這些都是比較底層的類和方法,修改得很差,可能會影響代碼執行。因此攔截調用前必定要充分理解。

5.一、攔截器接口

MyBatis插件經過實現攔截器接口Interceptor(org.apache.ibatis.plugin.Interceptor),便可在實現類中對攔截對象和方法進行處理。

攔截器接口Interceptor:

public interface Interceptor { Object intercept(Invocation invocation) throws Throwable; Object plugin(Object target); void setProperties(Properties properties); }

一、setProperties

二、plugin

三、intercept

5.二、攔截器簽名

經過攔截器註解,來代表這個攔截器須要攔截的接口和方法

@Intercepts(org.apache.ibatis.plugin.Intercepts)和@Signature(org.apache.ibatis.plugin.Signature)

@Intercepts註解中的屬性是一個@Signature(簽名)數組,能夠在同一個攔截器中同時攔截不一樣的接口和方法。

@Signature註解包含如下三個屬性。

  type:設置攔截的接口,可選值是前面提到的4個接口。

  method:設置攔截接口中的方法名,可選值是前面4個接口對應的方法,須要和接口匹配。

  args:設置攔截方法的參數類型數組,經過方法名和參數類型能夠肯定惟一一個方法。

0、簽名的寫法

type:接口類

method:方法名稱

args:要攔截的方法的參數類

下面例子爲Executor的update方法的簽名寫法

@Intercepts( @org.apache.ibatis.plugin.Signature( type = Executor.class, method = "update", args = { MappedStatement.class,Object.class })) public class ResultSetInterceptor implements Interceptor {

一、Executor接口

int update(MappedStatement ms,Object parameter) throws SQLException

該方法會在全部的 INSERT 、 UPDATE 、 DELETE  執行時被調用,所以若是想要攔截這 3 類操做,能夠攔截該方法

<E>List<E>query(MappedStatementms,Objectparameter,RowBoundsrowBounds,ResultHandlerresultHandler)throwsSQLException

該方法會在全部SELECT查詢方法執行時被調用。經過這個接口參數能夠獲取不少有用的信息,所以這是最常被攔截的一個方法。使用該方法須要注意的是,雖然接口中還有一個參數更多的同名接口,但因爲MyBatis的設計緣由,這個參數多的接口不能被攔截

<E> Cursor <E> queryCursor(MappedStatement ms,Object parameter,RowBounds rowBounds) throws SQLException

該方法只有在查詢的返回值類型爲 Cursor 時被調用。

List <BatchResult > flushStatements() throws SQLException

該方法只在經過 SqlSession 方法調用 flushStatements 方法或執行的接口方法中帶有 @Flush 註解時才被調用,

void commit(boolean required) throws SQLException

該方法只在經過 SqlSession 方法調用 commit 方法時才被調用,

void rollback(boolean required) throws SQLException

該方法只在經過 SqlSession 方法調用 rollback 方法時才被調用,

Transaction getTransaction()

該方法只在經過 SqlSession 方法獲取數據庫鏈接時才被調用,

void close(boolean forceRollback)

該方法只在延遲加載獲取新的 Executor 後纔會被執行,

boolean isClosed()

該方法只在延遲加載執行查詢方法前被執行,

二、ParameterHandler 接口

Object getParameterObject()

該方法只在執行存儲過程處理出參的時候被調用。

void setParameters(PreparedStatement ps) throws SQLException

該方法在全部數據庫方法設置 SQL 參數時被調用。

三、ResultSetHandler接口

<E> List <E> handleResultSets(Statement stmt) throws SQLException

該方法會在除存儲過程及返回值類型爲Cursor<T>(org.apache.ibatis.cursor.Cursor<T>)之外的查詢方法中被調用。

<E> Cursor <E> handleCursorResultSets(Statement stmt) throws SQLException;

該方法是 3.4.0 版本中新增長的,只會在返回值類型爲 Cursor <T>的查詢方法中被調用

void handleOutputParameters(CallableStatement cs) throws SQLException;

該方法只在使用存儲過程處理出參時被調用,ResultSetHandler接口的第一個方法對於攔截處理MyBatis的查詢結果很是有用,而且因爲這個接口被調用的位置在處理二級緩存以前,所以經過這種方式處理的結果能夠執行二級緩存。

四、StatementHandler接口

Statement prepare(Connection connection,Integer transactionTimeout) throws SQLException

該方法會在數據庫執行前被調用,優先於當前接口中的其餘方法而被執行

void parameterize(Statement statement) throws SQLException

該方法在prepare方法以後執行,用於處理參數信息

int batch(Statement statement) throws SQLException

在全局設置配置defaultExecutorType="BATCH"時,執行數據操做纔會調用該方法

<E> List <E> query(Statement statement,ResultHandler resultHandler) throws SQLException

執行SELECT方法時調用

<E> Cursor <E> queryCursor(Statement statement) throws SQLException

該方法是 3.4.0 版本中新增長的,只會在返回值類型爲Cursor<T>的查詢中被調用

5.三、補充,Spring Boot下使用攔截器 

Spring Boot下須要加入依賴

<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>${java.version}</source>
        <target>${java.version}</target>
    </configuration>
</plugin>

 

 

 

 

 

實例

一、基於Eclipse+Maven+SqlSession的實例

此用法比較底層,建議使用基於接口的用法。

本例子用Eclipse+Maven來建立這個實例,請先掌握Maven的相關知識

2.一、打開Eclipse,[File]->[New]->[Other],選擇Maven Project,而後下一步

二、勾上簡單項目選項,而後下一步

三、填入相關信息,而後點擊完成

 四、獲得的項目結構以下

五、修改pom文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>tk.mybatis</groupId>
    <artifactId>simple</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.6</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.12</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
View Code

六、準備數據庫數據

CREATE DATABASE mybatis DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; DROP TABLE IF EXISTS `country`; CREATE TABLE `country` ( `id` int(11) NOT NULL AUTO_INCREMENT, `countryname` varchar(255) DEFAULT NULL, `countrycode` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; INSERT INTO `country` VALUES ('1', '中國', 'CN'); INSERT INTO `country` VALUES ('2', '美國', 'US'); INSERT INTO `country` VALUES ('3', '俄羅斯', 'RU'); INSERT INTO `country` VALUES ('4', '英國', 'GB'); INSERT INTO `country` VALUES ('5', '法國', 'FR');
View Code

七、使用XML配置MyBatis

src/main/resources下建立mybatis-config.xml,注意修改MySql的ip地址和賬號密碼

<?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="LOG4J"/>
    </settings>
    
     <typeAliases>
        <package name="tk.mybatis.simple.model"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC">
                <property name="" value=""/>
            </transactionManager>
            <dataSource type="UNPOOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.16.137:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="tk/mybatis/simple/mapper/CountryMapper.xml"/>
    </mappers>
</configuration>
View Code

<settings> 中的 logImpl 屬性配置指定使用 LOG4J 輸出日誌

<typeAliases> 元素下面配置了一個包的別名,一般肯定一個類的時候須要使用類的全限定名稱,例如 tk.mybatis.simple.model.Country 。在 MyBatis 中須要頻繁用到類的全限定名稱,爲了方便使
用,咱們配置了 tk.mybatis.simple.model 包,這樣配置後,在使用類的時候不須要寫包名的部分,只使用 Country 便可。

<environments> 環境配置中主要配置了數據庫鏈接,數據庫的 url 爲 jdbc:mysql://localhost:3306/mybatis ,使用的是本機 MySQL 中的 mybatis 數據庫,後面的 username 和 password 分別是數據庫
的用戶名和密碼(若是你的數據庫用戶名及密碼和這裏的不同,請修改成本身數據庫可用的用戶名和密碼)

<mappers> 中配置了一個包含完整類路徑的 CountryMapper.xml ,這是一個 MyBatis 的 SQL 語句和映射配置文件

八、建立實體類

在src/main/java下建立包tk.mybatis.simple.model

而後建立一個類

package tk.mybatis.simple.model; public class Country { private Long id; private String countryname; private String countrycode; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getCountryname() { return countryname; } public void setCountryname(String countryname) { this.countryname = countryname; } public String getCountrycode() { return countrycode; } public void setCountrycode(String countrycode) { this.countrycode = countrycode; } }
View Code

九、添加Mapper文件

在src/main/resources下面建立tk/mybatis/simple/mapper目錄,再在該目錄下面建立CountryMapper.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="tk.mybatis.simple.mapper.CountryMapper">
    <select id="selectAll" resultType="Country"> select id,countryname,countrycode from country </select>
</mapper>
View Code

SQL 定義在 CountryMapper.xml 文件中,裏面的配置做用以下。
<mapper>: XML 的根元素,屬性 namespace 定義了當前 XML 的命名空間。
<select>元素:咱們所定義的一個 SELECT 查詢。
id 屬性:定義了當前 SELECT 查詢的惟一一個 id 。
resultType :定義了當前查詢的返回值類型,此處就是指實體類 Country ,前面配置中提到的別名主要用於這裏,若是沒有設置別名,此處就須要寫成 resultType= " tk.mybatis.simple.model.Country
"。
· select id , ... :查詢 SQL 語句。

十、配置log4j

在src/main/resources中添加log4j.properties配置文件

#\u5168\u5C40\u914D\u7F6E log4j.rootLogger=ERROR, stdout #MyBatis \u65E5\u5FD7\u914D\u7F6E log4j.logger.tk.mybatis.simple.mapper=TRACE #\u63A7\u5236\u53F0\u8F93\u51FA\u914D\u7F6E log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
View Code

日誌注意事項!
用過 Log4j 日誌組件的人可能都會知道,配置中的 log4j.logger.tk.mybatis.simple.mapper 對應的是 tk.mybatis.simple.mapper 包,可是在這個例子中, Java 目錄下並無這個包名,只在資源目錄下有
mapper 目錄。
在 MyBatis 的日誌實現中,所謂的包名其實是 XML 配置中的 namespace 屬性值的一部分。後面章節中介紹結合接口使用的相關內容時,因爲 namespace 屬性值必須和接口全限定類名相同,所以
纔會真正對應到 Java 中的包。當使用純註解方式時,使用的就是純粹的包名。
MyBatis 日誌的最低級別是 TRACE ,在這個日誌級別下, MyBatis 會輸出執行 SQL 過程當中的詳細信息,這個級別特別適合在開發時使用。

十一、編寫測試代碼

首先在 src/test/java  中建立 tk.mybatis.simple.mapper  包,而後建立 CountryMapperTest 測試類

package tk.mybatis.simple.mapper; import java.io.IOException; import java.io.Reader; import java.util.List; 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.BeforeClass; import org.junit.Test; import tk.mybatis.simple.model.Country; public class CountryMapperTest { private static SqlSessionFactory sqlSessionFactory; @BeforeClass public static void init(){ try { Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); } catch (IOException ignore) { ignore.printStackTrace(); } } @Test public void testSelectAll(){ SqlSession sqlSession = sqlSessionFactory.openSession(); try { List<Country> countryList = sqlSession.selectList("selectAll"); printCountryList(countryList); } finally { sqlSession.close(); } } private void printCountryList(List<Country> countryList){ for(Country country : countryList){ System.out.printf("%-4d%4s%4s\n",country.getId(), country.getCountryname(), country.getCountrycode()); } } }
View Code

對上面這段代碼作一個簡單的說明,具體以下。
· 經過 Resources 工具類將 mybatis-config.xml 配置文件讀入 Reader 。
· 再經過 SqlSessionFactoryBuilder 建造類使用 Reader 建立 SqlSessionFactory 工廠對象。在建立 SqlSessionFactory 對象的過程當中,首先解析 mybatis-config.xml 配置文件,讀取配置文件中的 mappers 配置後會
讀取所有的 Mapper.xml 進行具體方法的解析,在這些解析完成後, SqlSessionFactory 就包含了全部的屬性配置和執行 SQL 的信息。
· 使用時經過 SqlSessionFactory 工廠對象獲取一個 SqlSession 。
· 經過 SqlSession 的 selectList 方法查找到 CountryMapper.xml 中 id= " selectAll "的方法,執行 SQL 查詢。
· MyBatis 底層使用 JDBC 執行 SQL ,得到查詢結果集 ResultSet 後,根據 resultType 的配置將結果映射爲 Country 類型的集合,返回查詢結果。
· 這樣就獲得了最後的查詢結果 countryList ,簡單將結果輸出到控制檯。
· 最後必定不要忘記關閉 SqlSession ,不然會由於鏈接沒有關閉致使數據庫鏈接數過多,形成系統崩潰。

十二、測試

在testSelectAll方法上,右鍵,[Run as]->[JUnit],便可看到輸出結果

DEBUG [main] - ==> Preparing: select id,countryname,countrycode from country DEBUG [main] - ==> Parameters: TRACE [main] - <== Columns: id, countryname, countrycode TRACE [main] - <==        Row: 1, 中國, CN TRACE [main] - <==        Row: 2, 美國, US TRACE [main] - <==        Row: 3, 俄羅斯, RU TRACE [main] - <==        Row: 4, 英國, GB TRACE [main] - <==        Row: 5, 法國, FR DEBUG [main] - <==      Total: 5
1 中國 CN 2 美國 US 3 俄羅斯 RU 4 英國 GB 5     法國  FR
View Code

至此,例子完成

二、基於Spring Boot+Maven+接口+代碼生成器的實例

三、配置MyBatis

MyBatis的配置方式有如下幾種:一、使用XML文件配置;二、使用Spring Bean配置;三、使用Java編碼方式配置

這裏僅介紹最經常使用的XML文件配置方式

一、在src/main/resources下建立mybatis-config.xml

二、該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>
        <!-- 當查詢結果字段未null時,是否調用該字段的setter方法 -->
        <setting name="callSettersOnNulls" value="true" />
    </settings>

    <!--爲類型建立別名 -->
    <typeAliases>
        <typeAlias alias="Integer" type="java.lang.Integer" />
        <typeAlias alias="Long" type="java.lang.Long" />
        <typeAlias alias="HashMap" type="java.util.HashMap" />
        <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
        <typeAlias alias="ArrayList" type="java.util.ArrayList" />
        <typeAlias alias="LinkedList" type="java.util.LinkedList" />
    </typeAliases>


    <!--插件 -->
    <plugins>
        <!-- PageHelper4.1.1 -->
        <!--<plugin interceptor="com.github.pagehelper.PageHelper"> </plugin> -->
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!-- 這裏能夠對pagehelper進行配置,分別輸入參數名和參數的值,能夠查看相關文檔-->
            <property name="param1" value="value1" />
        </plugin>
    </plugins>
</configuration>
View Code

更詳盡的配置能夠查看:http://www.mybatis.org/mybatis-3/zh/configuration.html

一、動態傳入Top參數時,報錯

須要用括號把top後面的動態參數括起來

select top (#{pageSize}) from ...

四、【MyBatis】使用Eclipse插件的方式運行代碼生成器MBG(MyBatis Generator)

1、MyBatis Generator運行方式

MyBatis Generator有如下幾種運行方式:

a、Java代碼

b、命令提示行

c、Maven插件

d、Eclipse插件

其中只有Eclipse插件支持代碼合併,能夠生成新代碼的同時保留本身添加的代碼。

2、Eclipse插件使用步驟

a、安裝

下載插件: https:/github.com/mybatis/generator/releases

b、Eclipse中安裝插件

 選擇下載的壓縮包,而後一直下一步到完成,而後重啓Eclipse,即完成了安裝。

3、使用MBG插件

添加配置文件

src/main/resources下添加一個文件夾mybatis-generator,添加一個配置文件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>
    <classPathEntry location="C:\Softs\maven\Repository\com\microsoft\sqlserver\sqljdbc4\4.0\sqljdbc4-4.0.jar"/>
    
    <context id="SqlServerContext" targetRuntime="MyBatis3" defaultModelType="flat">
        <property name="javaFileEncoding" value="UTF-8" />
        <property name="autoDelimitKeywords" value="true" />
        <property name="beginningDelimiter " value="[" />
        <property name="endingDelimiter " value="]" />

        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="addRemarkComments" value="true"/>
        </commentGenerator>
        
        <jdbcConnection driverClass="com.microsoft.sqlserver.jdbc.SQLServerDriver" connectionURL="jdbc:sqlserver://127.0.0.1;database=db" userId="sa" password="psw">
        </jdbcConnection>
        
        <javaModelGenerator targetPackage="com.ltsolution.framework.bs.system.model" targetProject="framework\src\main\java">
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        
        <sqlMapGenerator targetPackage="mybatis.mapper" targetProject="framework\src\main\resources"/>
        
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.ltsolution.framework.bs.system.mapper" targetProject="framework\src\main\java"/>
        
        <table tableName="Company">
            <generatedKey column="RowId" sqlStatement="SQLServer" identity="true"/>
        </table>
        <table tableName="Customer">
            <generatedKey column="RowId" sqlStatement="JDBC" identity="true"/>
            <columnOverride column="RowId" isGeneratedAlways="true"></columnOverride>
        </table>
        <table tableName="CustomerType">
            <generatedKey column="RowId" sqlStatement="JDBC" identity="true"/>
            <columnOverride column="RowId" isGeneratedAlways="true"></columnOverride>
        </table>
        <table tableName="Product">
            <generatedKey column="RowId" sqlStatement="JDBC" identity="true"/>
            <columnOverride column="RowId" isGeneratedAlways="true"></columnOverride>
        </table>
        <table tableName="ProductType">
            <generatedKey column="RowId" sqlStatement="JDBC" identity="true"/>
            <columnOverride column="RowId" isGeneratedAlways="true"></columnOverride>
        </table>
        <table tableName="SaleShipmentDetail">
            <generatedKey column="RowId" sqlStatement="SQLServer" identity="true"/>
        </table>
        <table tableName="SaleShipmentHead">
            <generatedKey column="RowId" sqlStatement="SQLServer" identity="true"/>
            <ignoreColumn column="RowId" />
        </table>
        <table tableName="Storage">
            <generatedKey column="RowId" sqlStatement="SQLServer" identity="true"/>
        </table>
        <table tableName="HeadNoPrefix">
            <generatedKey column="RowId" sqlStatement="SQLServer" identity="true"/>
            <ignoreColumn column="RowId" />
        </table>
        <table tableName="StorageQuantity">
            <generatedKey column="RowId" sqlStatement="SQLServer" identity="true"/>
            <ignoreColumn column="RowId" />
        </table>
    </context>
</generatorConfiguration>
View Code

主要修改幾個地方

classPathEntry:設置數據庫驅動的jar包位置

context-jdbcConnection:設置數據庫信息

context-javaModelGenerator:設置model的生成位置

context-sqlMapGenerator:設置mapper.xml文件的生成位置

context-javaClientGenerator:設置mapper接口的生成位置

關於在SQL中使用的幾個注意點,能夠查看https://www.cnblogs.com/LiveYourLife/p/9000874.html這篇文章

其它的自行查閱詳細資料

啓動生成

便可看到生成的結果

五、使用MyBatis的分頁組件PageHelper時,多表關聯下使用別名查詢時,前臺傳參過來,根據參數排序的解決方案

場景:

使用SQLServer數據庫

有2個表Customer、CustomerType,都有字段TypeId

後臺SQL:select A.Name ,A.TypeId AS CTypeId, B.TypeName FROM Customer A LEFT JOIN CustomerType B ON A.TypeId = B.TypeId

傳給前臺的字段是:Name,CTypeId,TypeName

前臺要求查詢條件:要求按CTypeId字段排序,而且分頁查詢1~3條記錄

有2個解決方式:

  a、【此方法效率可能較低】使用子查詢,先把整個表查出來,而後按照TypeName排序並分頁(PageHelper的5.1.3版本是這樣實現的)

  生成sql以下,一個由3個查詢組成

SELECT TOP 3 Name,CTypeId,TypeName FROM ( SELECT ROW_NUMBER() OVER (ORDER BY CTypeId DESC) PAGE_ROW_NUMBER, Name, CTypeId, TypeName FROM ( SELECT A.Name, A.TypeId AS CTypeId ,B.TypeName  FROM Customer A LEFT JOIN CustomerType B ON A.TypeId = B.TypeId ) AS PAGE_TABLE_ALIAS ) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 0 ORDER BY PAGE_ROW_NUMBER

  b、【個人解決方案】將前臺傳過來的字段,解析成對應字段(上面例子中,將TypeName解析成A.name),插入到語句中,便可獲得分頁結果

  對應的sql,節省了一個查詢

SELECT TOP 3 Name,CTypeId,TypeName FROM ( SELECT ROW_NUMBER() OVER (ORDER BY A.TypeId DESC) PAGE_ROW_NUMBER, A.Name, A.TypeId AS CTypeId ,B.TypeName FROM Customer A LEFT JOIN CustomerType B ON A.TypeId = B.TypeId ) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 0 ORDER BY PAGE_ROW_NUMBER

實現:

一、使用5.1.3版本的源碼

二、修改SqlServer對應的解析器

這個解析器我是從舊的版本(不記得是否是4.1.7)基礎上修改的,那個版本還未支持上面第一種方式的排序分頁,因此當時是不能排序並分頁的

主要修改了addRowNumber方法,整個文件代碼以下

/* * The MIT License (MIT) * * Copyright (c) 2014 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.parser; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import com.github.pagehelper.PageException; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.operators.relational.GreaterThan; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; import net.sf.jsqlparser.statement.select.FromItem; import net.sf.jsqlparser.statement.select.Join; import net.sf.jsqlparser.statement.select.LateralSubSelect; import net.sf.jsqlparser.statement.select.OrderByElement; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SelectBody; import net.sf.jsqlparser.statement.select.SelectExpressionItem; import net.sf.jsqlparser.statement.select.SelectItem; import net.sf.jsqlparser.statement.select.SetOperationList; import net.sf.jsqlparser.statement.select.SubJoin; import net.sf.jsqlparser.statement.select.SubSelect; import net.sf.jsqlparser.statement.select.Top; import net.sf.jsqlparser.statement.select.ValuesList; import net.sf.jsqlparser.statement.select.WithItem; /** * 將sqlserver查詢語句轉換爲分頁語句<br> * 注意事項:<br> * <ol> * <li>請先保證你的SQL能夠執行</li> * <li>sql中最好直接包含order by,能夠自動從sql提取</li> * <li>若是沒有order by,能夠經過入參提供,可是須要本身保證正確</li> * <li>若是sql有order by,能夠經過orderby參數覆蓋sql中的order by</li> * <li>order by的列名不能使用別名</li> * <li>表和列使用別名的時候不要使用單引號(')</li> * </ol> * 該類設計爲一個獨立的工具類,依賴jsqlparser,能夠獨立使用 * * @author liuzh */
public class SqlServerParser { // 緩存結果 protected static final Map<String, String> CACHE = new ConcurrentHashMap<String, String>(); // 開始行號 protected static final String START_ROW = String.valueOf(Long.MIN_VALUE); // 結束行號 protected static final String PAGE_SIZE = String.valueOf(Long.MAX_VALUE); // 外層包裝表 protected static final String WRAP_TABLE = "WRAP_OUTER_TABLE"; // 表別名名字 protected static final String PAGE_TABLE_NAME = "PAGE_TABLE_ALIAS"; // protected public static final Alias PAGE_TABLE_ALIAS = new Alias(PAGE_TABLE_NAME); // 行號 protected static final String PAGE_ROW_NUMBER = "PAGE_ROW_NUMBER"; // 行號列 protected static final Column PAGE_ROW_NUMBER_COLUMN = new Column(PAGE_ROW_NUMBER); // TOP 100 PERCENT protected static final Top TOP100_PERCENT; // 靜態方法處理 static { TOP100_PERCENT = new Top(); TOP100_PERCENT.setExpression(new LongValue(100)); TOP100_PERCENT.setPercentage(true); } /** * 轉換爲分頁語句 * * @param sql * @param offset * @param limit * @return */
    public String convertToPageSql(String sql, int offset, int limit) { String pageSql = CACHE.get(sql); if (pageSql == null) { // 解析SQL Statement stmt; try { stmt = CCJSqlParserUtil.parse(sql); } catch (Throwable e) { throw new RuntimeException("不支持該SQL轉換爲分頁查詢!"); } if (!(stmt instanceof Select)) { throw new RuntimeException("分頁語句必須是Select查詢!"); } // 獲取分頁查詢的select Select pageSelect = getPageSelect((Select) stmt); pageSql = pageSelect.toString(); CACHE.put(sql, pageSql); } pageSql = pageSql.replace(START_ROW, String.valueOf(offset)); pageSql = pageSql.replace(PAGE_SIZE, String.valueOf(limit)); return pageSql; } /** * 獲取一個外層包裝的TOP查詢 * * @param select * @return */ protected Select getPageSelect(Select select) { SelectBody selectBody = select.getSelectBody(); if (selectBody instanceof SetOperationList) { selectBody = wrapSetOperationList((SetOperationList) selectBody); } // 這裏的selectBody必定是PlainSelect if (((PlainSelect) selectBody).getTop() != null) { throw new RuntimeException("被分頁的語句已經包含了Top,不能再經過分頁插件進行分頁查詢!"); } // 獲取查詢列 List<SelectItem> selectItems = getSelectItems((PlainSelect) selectBody); // 對一層的SQL增長ROW_NUMBER() addRowNumber((PlainSelect) selectBody); // 處理子語句中的order by processSelectBody(selectBody, 0); // 新建一個select Select newSelect = new Select(); PlainSelect newSelectBody = new PlainSelect(); // 設置top Top top = new Top(); top.setExpression(new LongValue(Long.MAX_VALUE)); newSelectBody.setTop(top); // 設置order by List<OrderByElement> orderByElements = new ArrayList<OrderByElement>(); OrderByElement orderByElement = new OrderByElement(); orderByElement.setExpression(PAGE_ROW_NUMBER_COLUMN); orderByElements.add(orderByElement); newSelectBody.setOrderByElements(orderByElements); // 設置where GreaterThan greaterThan = new GreaterThan(); greaterThan.setLeftExpression(PAGE_ROW_NUMBER_COLUMN); greaterThan.setRightExpression(new LongValue(Long.MIN_VALUE)); newSelectBody.setWhere(greaterThan); // 設置selectItems newSelectBody.setSelectItems(selectItems); // 設置fromIterm SubSelect fromItem = new SubSelect(); fromItem.setSelectBody(selectBody); fromItem.setAlias(PAGE_TABLE_ALIAS); newSelectBody.setFromItem(fromItem); newSelect.setSelectBody(newSelectBody); if (isNotEmptyList(select.getWithItemsList())) { newSelect.setWithItemsList(select.getWithItemsList()); } return newSelect; } /** * 包裝SetOperationList * * @param setOperationList * @return */ protected SelectBody wrapSetOperationList(SetOperationList setOperationList) { // 獲取最後一個plainSelect SelectBody setSelectBody = setOperationList.getSelects().get(setOperationList.getSelects().size() - 1); if (!(setSelectBody instanceof PlainSelect)) { throw new RuntimeException("目前沒法處理該SQL,您能夠將該SQL發送給abel533@gmail.com協助做者解決!"); } PlainSelect plainSelect = (PlainSelect) setSelectBody; PlainSelect selectBody = new PlainSelect(); List<SelectItem> selectItems = getSelectItems(plainSelect); selectBody.setSelectItems(selectItems); // 設置fromIterm SubSelect fromItem = new SubSelect(); fromItem.setSelectBody(setOperationList); fromItem.setAlias(new Alias(WRAP_TABLE)); selectBody.setFromItem(fromItem); // order by
        if (isNotEmptyList(plainSelect.getOrderByElements())) { selectBody.setOrderByElements(plainSelect.getOrderByElements()); plainSelect.setOrderByElements(null); } return selectBody; } /** * 獲取查詢列 * * @param plainSelect * @return */ protected List<SelectItem> getSelectItems(PlainSelect plainSelect) { // 設置selectItems List<SelectItem> selectItems = new ArrayList<SelectItem>(); for (SelectItem selectItem : plainSelect.getSelectItems()) { // 別名須要特殊處理 if (selectItem instanceof SelectExpressionItem) { SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem; if (selectExpressionItem.getAlias() != null) { // 直接使用別名 Column column = new Column(selectExpressionItem.getAlias().getName()); SelectExpressionItem expressionItem = new SelectExpressionItem(column); selectItems.add(expressionItem); } else if (selectExpressionItem.getExpression() instanceof Column) { Column column = (Column) selectExpressionItem.getExpression(); SelectExpressionItem item = null; if (column.getTable() != null) { Column newColumn = new Column(column.getColumnName()); item = new SelectExpressionItem(newColumn); selectItems.add(item); } else { selectItems.add(selectItem); } } else { selectItems.add(selectItem); } } else if (selectItem instanceof AllTableColumns) { selectItems.add(new AllColumns()); } else { selectItems.add(selectItem); } } return selectItems; } /** * 最外層的SQL查詢須要增長ROW_NUMBER() * * @param plainSelect */ protected void addRowNumber(PlainSelect plainSelect) { // 增長ROW_NUMBER() StringBuilder orderByBuilder = new StringBuilder(); orderByBuilder.append("ROW_NUMBER() OVER ("); if (isNotEmptyList(plainSelect.getOrderByElements())) { // ByLouis 使用別名,自動找出哪一列,而後進行排序 for (OrderByElement orderByElement : plainSelect.getOrderByElements()) { String orderName = orderByElement.getExpression().toString(); // 若是排序列已經帶.,如A.TypeId,則不用處理 int indexOfPoint = orderName.indexOf("."); if (indexOfPoint >= 0) break; // 找出排序列名 String realFieldName = ""; for (SelectItem selectItem : plainSelect.getSelectItems()) { // 首先找到前臺傳過來的字段所在的列 // selectItem.toString()能夠有4種格式 // 直接select字段:HelpCode // 表加字段:A.HelpCode // 直接select字段加別名:HelpCode as NewCode // 表加字段加別名:A.HelpCode as NewCode // 前臺傳過來的字段:有別名則是別名,列名則是列名 // 查找規則:最後一個空格,或最後一個.後面的數據 String selectName = selectItem.toString(); int lastIndexOfSpace = selectName.lastIndexOf(" "); int lastIndexOfPoint = selectName.lastIndexOf("."); int startGetIndex = 0; if (lastIndexOfSpace > startGetIndex) startGetIndex = lastIndexOfSpace; if (lastIndexOfPoint > startGetIndex) startGetIndex = lastIndexOfPoint; if (startGetIndex == 0) startGetIndex = 1; else startGetIndex++; String fieldName = selectName.substring(startGetIndex); System.out.println(fieldName); if (fieldName.toUpperCase().equals(orderName.toUpperCase())) { realFieldName = selectName; // 找到對應select的字段 // 查找規則 第一個空格前面 int firstIndexOfSpace = selectName.indexOf(" "); if (firstIndexOfSpace >= 0) realFieldName = realFieldName.substring(0, firstIndexOfSpace); break; } } orderByElement.setExpression(new Column(realFieldName)); } orderByBuilder.append(PlainSelect.orderByToString(false, plainSelect.getOrderByElements())); } else { throw new RuntimeException("請您在sql中包含order by語句!"); } // 須要把改orderby清空 if (isNotEmptyList(plainSelect.getOrderByElements())) { plainSelect.setOrderByElements(null); } orderByBuilder.append(") "); orderByBuilder.append(PAGE_ROW_NUMBER); Column orderByColumn = new Column(orderByBuilder.toString()); plainSelect.getSelectItems().add(0, new SelectExpressionItem(orderByColumn)); } /** * 處理selectBody去除Order by * * @param selectBody */ protected void processSelectBody(SelectBody selectBody, int level) { if (selectBody instanceof PlainSelect) { processPlainSelect((PlainSelect) selectBody, level + 1); } else if (selectBody instanceof WithItem) { WithItem withItem = (WithItem) selectBody; if (withItem.getSelectBody() != null) { processSelectBody(withItem.getSelectBody(), level + 1); } } else { SetOperationList operationList = (SetOperationList) selectBody; if (operationList.getSelects() != null && operationList.getSelects().size() > 0) { List<SelectBody> plainSelects = operationList.getSelects(); for (SelectBody plainSelect : plainSelects) { processSelectBody(plainSelect, level + 1); } } } } /** * 處理PlainSelect類型的selectBody * * @param plainSelect */ protected void processPlainSelect(PlainSelect plainSelect, int level) { if (level > 1) { if (isNotEmptyList(plainSelect.getOrderByElements())) { if (plainSelect.getTop() == null) { plainSelect.setTop(TOP100_PERCENT); } } } if (plainSelect.getFromItem() != null) { processFromItem(plainSelect.getFromItem(), level + 1); } if (plainSelect.getJoins() != null && plainSelect.getJoins().size() > 0) { List<Join> joins = plainSelect.getJoins(); for (Join join : joins) { if (join.getRightItem() != null) { processFromItem(join.getRightItem(), level + 1); } } } } /** * 處理子查詢 * * @param fromItem */ protected void processFromItem(FromItem fromItem, int level) { if (fromItem instanceof SubJoin) { SubJoin subJoin = (SubJoin) fromItem; if (subJoin.getJoin() != null) { if (subJoin.getJoin().getRightItem() != null) { processFromItem(subJoin.getJoin().getRightItem(), level + 1); } } if (subJoin.getLeft() != null) { processFromItem(subJoin.getLeft(), level + 1); } } else if (fromItem instanceof SubSelect) { SubSelect subSelect = (SubSelect) fromItem; if (subSelect.getSelectBody() != null) { processSelectBody(subSelect.getSelectBody(), level + 1); } } else if (fromItem instanceof ValuesList) { } else if (fromItem instanceof LateralSubSelect) { LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem; if (lateralSubSelect.getSubSelect() != null) { SubSelect subSelect = lateralSubSelect.getSubSelect(); if (subSelect.getSelectBody() != null) { processSelectBody(subSelect.getSelectBody(), level + 1); } } } // Table時不用處理 } /** * List不空 * * @param list * @return */
    public boolean isNotEmptyList(List<?> list) { if (list == null || list.size() == 0) { return false; } return true; } /** * 轉換爲分頁語句 * * @param sql * @return */
    public String convertToPageSql(String sql) { return convertToPageSql(sql, null, null); } /** * 轉換爲分頁語句 * * @param sql * @param offset * @param limit * @return */
    public String convertToPageSql(String sql, Integer offset, Integer limit) { // 解析SQL Statement stmt; try { stmt = CCJSqlParserUtil.parse(sql); } catch (Throwable e) { throw new PageException("不支持該SQL轉換爲分頁查詢!"); } if (!(stmt instanceof Select)) { throw new PageException("分頁語句必須是Select查詢!"); } // 獲取分頁查詢的select Select pageSelect = getPageSelect((Select) stmt); String pageSql = pageSelect.toString(); // 緩存移到外面了,因此不替換參數 if (offset != null) { pageSql = pageSql.replace(START_ROW, String.valueOf(offset)); } if (limit != null) { pageSql = pageSql.replace(PAGE_SIZE, String.valueOf(limit)); } return pageSql; } }
View Code

六、MyBatis Generator代碼生成器問題

MyBatis+SqlServer中,主鍵字段不要生成到插入語句中

<table tableName="Customer">
    <columnOverride column="RowId" isGeneratedAlways="true"></columnOverride>
</table>

MyBatis+SqlServer中,插入後返回主鍵值

代碼生成器原來寫法:

<table tableName="Customer">
    <generatedKey column="RowId" sqlStatement="SQLServer" identity="true"/>
</table>

生成Mapper中的Insert語句:

<insert id="insert" parameterType="com.LTSolution.ShopApp.Model.Customer">
  <selectKey keyProperty="rowid" order="AFTER" resultType="java.lang.Integer"> SELECT SCOPE_IDENTITY() </selectKey> insert into Company (...) values (...) </insert>

按照查看相關書籍和資料,這個寫法應該是可行的,可是實際不行。

通過測試使用下面的寫法成功插入後返回主鍵

代碼生成器寫法:

<table tableName="Customer">
    <generatedKey column="RowId" sqlStatement="JDBC" identity="true"/>
</table>

生成Mapper中的Insert語句:

<insert id="insert" keyColumn="RowId" keyProperty="rowid" parameterType="com.LTSolution.ShopApp.Model.Customer" useGeneratedKeys="true"> insert into Customer (...) values (...) </insert>

七、分頁組件PageHelper和SQLServer的多表關聯分頁查詢問題

原來使用4.1.7,當2個表關聯查詢的時候若是有同名,Select的時候給予了別名,使用PageHelper.orderBy("別名"),會出現錯誤

由於生成的語句是

SELECT TOP 3 Name,CTypeId FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY TypeId DESC) PAGE_ROW_NUMBER, A.Name,A.TypeId as CTypeId FROM Customer A LEFT JOIN CustomerType B ON A.TypeId = B.TypeId ) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 0 
ORDER BY PAGE_ROW_NUMBER

由於(ORDER BY TypeId DESC)中TypeId是不知道哪一個表的

後來查看更新記錄,後面的版本更新了這個問題

如今使用最新版本5.1.3,生成的語句是

SELECT TOP 3 Name,CTypeId FROM ( SELECT ROW_NUMBER() OVER (ORDER BY CTypeId DESC) PAGE_ROW_NUMBER, Name, CTypeId FROM ( SELECT A.Name, A.TypeId AS CTypeId FROM Customer A LEFT JOIN CustomerType B ON A.TypeId = B.TypeId ) AS PAGE_TABLE_ALIAS ) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 0 ORDER BY PAGE_ROW_NUMBER

可見其中增長了一個子查詢,解決了這個問題

返回值爲Map時,若是select的結果中某個字段的值全是空,默認不添加到Map中,須要改成把控制添加到Map中

使用select,返回值爲Map,結果一些空的字段,不會寫到Map中,致使前端接收不到該字段的值

只須要在mybatis-config.xml配置文件中加入一下設置代碼便可(注意,要寫到前面,寫到後面XML文件會報錯)

<configuration>
    <settings>
        <setting name="callSettersOnNulls" value="true" />
    </settings>
</configuration>

八、MyBatis鏈接SQL Server

1.1的例子中使用MyBatis鏈接MySQL數據庫,若是使用SQL Server數據庫,能夠進行如下設置

一、pom文件中添加SQL Server鏈接的依賴

<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>sqljdbc4</artifactId>
    <version>4.0</version>
</dependency>

二、修改MyBatis的配置

<dataSource type="UNPOOLED">
    <property name="driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
    <property name="url" value="jdbc:sqlserver://127.0.0.1;database=mybatis;" />
    <property name="username" value="sa" />
    <property name="password" value="sa" />
</dataSource>
相關文章
相關標籤/搜索