1. 程式人生 > >TKmybatis的框架介紹及使用方法

TKmybatis的框架介紹及使用方法

最近專案使用了SpringBoot+TKMytis框架,期間遇到一些問題,順便記一下。

一、框架配置

配置的話非常簡單,我用的是SpringBoot,直接引入:

<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>2.0.3-beta1</version>
</dependency>

<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper</artifactId>
    <version>4.0.0</version>
</dependency>

Mybatis的以及分頁外掛等就不寫了。

建立一個BaseMapper

public interface BaseMapper<T> extends tk.mybatis.mapper.common.BaseMapper<T>, MySqlMapper<T>, IdsMapper<T>, ConditionMapper<T>,ExampleMapper<T> {

}

這5個Mapper待會我會詳細講解。

建立BaseService<T>繼承自BaseMapper<T>

public interface BaseService<T> extends BaseMapper<T> {
}

以及BaseService的實現類BaseServiceImpl<T> implements BaseService<T>

public abstract class BaseServiceImpl<T> implements BaseService<T> {
}

Service裡需實現部分方法,詳細程式碼在後邊。

這樣我們就基本完成了配置。

二、類配置方法

1、實體類

建立一個實體類與資料庫進行對映,此時我們使用JPA的註解:

package com.capol.entity;

import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;

import com.capol.base.BaseEntity;

import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * @author lizihao
 * @version 2018年07月31日
 * 使用者角色
 */
@Data
@EqualsAndHashCode(callSuper=false)
@Table(name="t_sys_user_role")//設定資料庫中表名字
public class UserRole extends BaseEntity{

	/**
	 * 主鍵
	 */
	@Column(name = "f_id")
	@Id
	private String fId;
	
	/**
	 * 使用者ID
	 */
	@Column(name = "f_user_id")
	private String fUserId;
	
	/**
	 * 使用者名稱
	 */
	@Transient
	private String fUserName;
	
}

其中@Table即資料表表名,@Column即列名,@Id作為主鍵,需要注意,@Id註解不可有多個,@Transient即冗餘欄位,不與資料庫任何欄位對應。

分享一個小技巧,實際專案中我們可能存在多資料來源的情況,如果使用的是sqlserver,且多個數據庫均在同一臺伺服器下且配置的賬號均擁有許可權,

則@Table註解中可以寫成“{資料庫名}.{架構名}.{表名}”,如:@Table(name="db.dbo.tableName")

而不需要再額外配置資料來源

2、Service類

這裡主要是實現了上邊BaseMapper中繼承的5個Mapper的方法,

tk.mybatis.mapper.common.BaseMapper<T>中有較多方法,均需要繼承實現:

        /**
	 * 儲存一個實體,null屬性也會儲存
	 * 
	 * @param record
	 * @return
	 */
	int insert(T record);

	/**
	 * 儲存一個實體,null屬性不會儲存
	 * 
	 * @param record
	 * @return
	 */
	int insertSelective(T record);

	/**
	 * 根據實體屬性作為條件進行刪除,查詢條件使用等號
	 */
	int delete(T record);

	/**
	 * 根據主鍵更新屬性不為null的值
	 */
	int updateByPrimaryKeySelective(T record);

	/**
	 * 根據實體中的屬性值進行查詢,查詢條件使用等號
	 */
	List<T> select(T record);

	/**
	 * 查詢全部結果,select(null)方法能達到同樣的效果
	 */
	List<T> selectAll();

	/**
	 * 根據實體中的屬性進行查詢,只能有一個返回值,有多個結果是丟擲異常,查詢條件使用等號
	 */
	T selectOne(T record);

	/**
	 * 根據實體中的屬性查詢總數,查詢條件使用等號
	 */
	int selectCount(T record);

以上所有方法的查詢條件均為實體類record中的非空屬性。

MySqlMapper<T>中的方法如下:

	/**
	 * 批量插入,支援批量插入的資料庫可以使用,例如MySQL,H2等,另外該介面限制實體包含`id`屬性並且必須為自增列
	 */
	public int insertList(List<T> recordList);

	/**
	 * 插入資料,限制為實體包含`id`屬性並且必須為自增列,實體配置的主鍵策略無效
	 */
	public int insertUseGeneratedKeys(T record);

這兩個方法就比較坑了,限制了主鍵必須為自增列,如果是自己生成主鍵則不能使用該方法。

IdsMapper<T>中的方法如下:

        /**
	 * 根據主鍵@Id進行查詢,多個Id以逗號,分割
	 * @param id
	 * @return
	 */
	List<T> selectByIds(String ids);
	
	/**
	 * 根據主鍵@Id進行刪除,多個Id以逗號,分割
	 * @param id
	 * @return
	 */
	int deleteByIds(String ids);

這兩個方法就很好理解了,不再解釋。

ConditionMapper<T>中的方法如下:

        /**
	 * 根據Condition條件進行查詢
	 */
	public List<T> selectByCondition(Object condition);

	/**
	 * 根據Condition條件進行查詢
	 */
	public int selectCountByCondition(Object condition);

	/**
	 * 根據Condition條件刪除資料,返回刪除的條數
	 */
	public int deleteByCondition(Object condition);

	/**
	 * 根據Condition條件更新實體`record`包含的全部屬性,null值會被更新,返回更新的條數
	 */
	public int updateByCondition(T record, Object condition);

	/**
	 * 根據Condition條件更新實體`record`包含的全部屬性,null值會被更新,返回更新的條數
	 */
	public int updateByConditionSelective(T record, Object condition);

傳入的Object condition應為tk.mybatis.mapper.entity.Condition,具體使用方法後續會說明。

ExampleMapper<T>中的方法如下:

        /**
	 * 根據Example條件進行查詢
	 */
	public List<T> selectByExample(Object example);

	/**
	 * 根據Example條件進行查詢,若有多條資料則丟擲異常
	 */
	public T selectOneByExample(Object example);

	/**
	 * 根據Example條件進行查詢總數
	 */
	public int selectCountByExample(Object example);

	/**
	 * 根據Example條件刪除資料,返回刪除的條數
	 */
	public int deleteByExample(Object example);

	/**
	 * 根據Example條件更新實體`record`包含的全部屬性,null值會被更新,返回更新的條數
	 */
	public int updateByExample(T record, Object example);

	/**
	 * 根據Example條件更新實體`record`包含的不是null的屬性值,返回更新的條數
	 */
	public int updateByExampleSelective(T record, Object example);

同上,傳入的Object example應為tk.mybatis.mapper.entity.Example,具體使用方法後續會說明。

3、實現類

各個方法的實現大同小異,此處以一個為例:

public abstract class BaseServiceImpl<T> implements BaseService<T> {

	protected abstract BaseMapper<T> getMapper();

	@Override
	public int insert(T record) {
		return getMapper().insert(record);
	}
}

getMapper()方法需要在具體的業務程式碼中實現,其餘不再贅述。

三、使用方法

1、tk.mybatis.mapper.common.BaseMapper<T>, IdsMapper<T>, MySqlMapper<T>內方法使用說明:

從介面中我們可以看到傳入的方法基本均為T record,即實體類,查詢時會根據實體類中的屬性值進行where語句構建,查詢條件為等號,這裡沒有什麼特殊的。

不過需要注意,若傳入例項化的實體類,且其中包含int屬性,則構建sql語句中會將該屬性包含進去,如下程式碼:

@Data
@EqualsAndHashCode(callSuper=false)
@Table(name="t_sys_user_role")//設定資料庫中表名字
public class UserRole extends BaseEntity{

	/**
	 * 主鍵
	 */
	@Column(name = "f_id")
	@Id
	private String fId;
	
	/**
	 * 型別(1.系統管理員)
	 */
	@Column(name = "f_type")
	private int fType;
}

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=StartApp.class)
@WebAppConfiguration
public class TestService {
	
	@Autowired
	private IUserRoleService userRoleService;

        @Test
	public void testUserRole() throws Exception{
		UserRole userRole = new UserRole();
		List<UserRole> userRoleList = userRoleService.select(userRole);
		System.out.println(userRoleList);
	}
}

從日誌中我們可以看到:

2018-08-12 17:31:10.768 DEBUG 12172 --- [           main] com.capol.mapper.UserRoleMapper.select   : ==>  Preparing: SELECT f_id,f_user_id,f_type,f_status,f_description,f_creator_id,f_create_time,f_last_updator_id,f_last_update_time FROM t_sys_user_role WHERE f_type = ? 
2018-08-12 17:31:10.776 DEBUG 12172 --- [           main] com.capol.mapper.UserRoleMapper.select   : ==> Parameters: 0(Integer)
2018-08-12 17:31:10.787 DEBUG 12172 --- [           main] com.capol.mapper.UserRoleMapper.select   : <==      Total: 0

很明顯,這不是我們要的結果。將int型別改為Integer型別即可,或使用Condition、Example方法進行查詢。

2、ExampleMapper<T>內方法使用說明:

所有方法均需要傳入tk.mybatis.mapper.entity.Example,

首先進行例項化:

Example example = new Example(UserRole.class);//例項化
Example.Criteria criteria = example.createCriteria();

 Criteria是Example中的一個內部類,在最終sql構建時以括號呈現,Criteria裡帶了較多構建查詢條件的方法,如

andEqualTo(String property, Object value),

orEqualTo(String property, Object value),

andGreaterThan(String property, Object value),

orGreaterThan(String property, Object value)

傳入的property為實體類中的屬性名,非資料度欄位名。

舉例說明,如orEqualTo(String property, Object value),程式碼如下:

Example example = new Example(UserRole.class);//例項化
Example.Criteria criteria = example.createCriteria();
criteria.orEqualTo("fUserId", "15693a6e509ee4819fcf0884ea4a7c9b");
criteria.orEqualTo("fUserId", "15ccaf3e89376f7b109eec94d10b7988");
List<UserRole> userRoleList = userRoleService.selectByExample(example);

最終的where語句則為:

( f_user_id = "15693a6e509ee4819fcf0884ea4a7c9b" or f_user_id = "15ccaf3e89376f7b109eec94d10b7988" )

其餘方法同理。 

其中andCondition(String condition)方法支援手寫條件,傳入的字串為最終的查詢條件,如:length(f_user_id)<5

以及likeTo()的方法是不帶百分號%的,需要自己對傳入引數進行構建(加左like或者右like等)。

其餘方法自行見原始碼,不再贅述。

3、ConditionMapper<T>內方法使用說明:

所有方法均需要傳入tk.mybatis.mapper.entity.Condition,Condition實際上繼承自tk.mybatis.mapper.entity.Example,

原始碼中只有三個方法:

public Condition(Class<?> entityClass) {
    super(entityClass);
}

public Condition(Class<?> entityClass, boolean exists) {
    super(entityClass, exists);
}

public Condition(Class<?> entityClass, boolean exists, boolean notNull) {
    super(entityClass, exists, notNull);
}

說實話我也不知道這樣做有什麼意義,望哪位大神指教一下。

boolean exists, boolean notNull這兩個引數的含義為:

若exists為true時,如果欄位不存在就丟擲異常,false時,如果不存在就不使用該欄位的條件,

若notNull為true時,如果值為空,就會丟擲異常,false時,如果為空就不使用該欄位的條件

其使用方法與Example類似:

Condition condition = new Condition(UserRole.class);
Criteria criteria = condition.createCriteria();
criteria.orEqualTo("fUserId", "15693a6e509ee4819fcf0884ea4a7c9b");
criteria.orEqualTo("fUserId", "15ccaf3e89376f7b109eec94d10b7988");
List<UserRole> userRoleList = userRoleService.selectByCondition(condition);

畢竟是繼承自Example。

4、Example.and()/or()和Condition.and()/or()方法說明:

兩個都一樣,我就挑一個說吧。

例項化方法跟上邊略有不同:

Condition condition = new Condition(UserRole.class);
//Criteria criteria1 = condition.createCriteria();
Criteria criteria1 = condition.and();

上邊說了,每個Criteria在最終結果中以括號形式展現,此時and()方法則表示 and (Criteria中的條件),or()方法則表示 or (Criteria中的條件),預設createCriteria()等同於and(),測試結果如下:

2018-08-12 18:23:11.805 DEBUG 13760 --- [           main] c.c.m.UserRoleMapper.selectByCondition   : ==>  Preparing: SELECT f_id,f_user_id,f_type,f_status,f_description,f_creator_id,f_create_time,f_last_updator_id,f_last_update_time FROM t_sys_user_role WHERE ( f_user_id = ? and f_user_id = ? ) or ( f_description = ? or f_description = ? )