1. 程式人生 > >mybatis免sql外掛之JpaMapper-以Jpa hibernate的風格寫mybatis(mybatis實現簡單分表-sharding功能)

mybatis免sql外掛之JpaMapper-以Jpa hibernate的風格寫mybatis(mybatis實現簡單分表-sharding功能)

mybatis免sql外掛之JpaMapper-以Jpa hibernate的風格寫mybatis(mybatis實現簡單分表-sharding功能)

簡介

JpaMapper以Jpa hibernate的風格寫mybatis的程式碼,可以減少手動寫sql的煩惱。

優勢:

  1. 不替換底層實現,僅生成sql並交給mybatis
  2. 方法基本與Jpa hibernate相似,易於框架替換,當然,沒那麼厲害,不支援聯表哦,專案還在繼續完善中。
  3. 提供簡單分表功能
  4. 邏輯簡單,可以拿去自己定製

gitee地址:https://gitee.com/xiaoyaofeiyang/JpaMapper

github地址:https://github.com/feiyangtianyao/jpa-mapper

上篇介紹主鍵id生成策略和useGeneratedKeys無效的場景。這一篇將介紹如何使用mybatis做簡單分表。

mybatis的bind

bind是什麼

bind標籤可以使用OGNL表示式建立一個變數並將其繫結到上下文中。大家都這樣說。

為什麼會有bind呢?

使用concat函式連線字串,在MySQL中,這個函式支援多個引數,但是在Oracle中只支援兩個引數。 由於不同資料庫之間的語法差異,如果更換了資料庫,有些SQL語句可能就需要重寫。 針對這種情況,可以使用bind標籤來避免由於更換資料庫帶來的一些麻煩。 我們將上面的語句改為bind方式。大家都這樣說。

bind示例

<if test=” userNarne != null and userNarne !=””>
<bind narne= " userNarneLike ” value = ”’ 草 ’+ userNarne + ’ 每 ’” />
and user name like #{userNarneLike}
</if>

這裡是用bind做了個簡單的運算。

KeyGenerator是主鍵生成策略的介面,實現KeyGenerator的類主要有三個:

  1. Jdbc3KeyGenerator,其實就是自增策略
  2. NoKeyGenerator,顧名思義就是啥也沒有。
  3. SelectKeyGenerator,解析SelectKey註解定義的主鍵策略。

bind還能做分表

為了實現我們的分表(sharding)功能,我們需要思考sql語句怎樣才能實現分表,因為mybatis只能根據我們的sql語句來進行CRUD,並不能做程式上的分表。

CUD操作只能是單表,所以註定我們的分表功能的CUD只能是單表,根據分表字段找到對應表,雖然功能並不是很強大,但足夠大多數場景使用了。

R操作可以使用Union操作連線多個相同表的查詢資料,因為我們可以將查詢操作擴充套件到多表。當然,無法支援太複雜查詢。

這裡列出一個簡單的Insert操作分表的示例:

@Insert({
	"<script>",
	 	"<bind name=\"tableName\" value=\"item.getIdentifyTable()\" />",
        "INSERT INTO ${tableName}",        "(chat_no,uid,opp_id,user_id,user_type,course_id,live_id,nickname,chat_time,chat_type,target_uid,content,create_time,update_time)",
        "values ",
        "(",
		"#{item.chatNo},",
		"#{item.uid},",
		"#{item.oppId},",
		"#{item.userId},",
		"#{item.userType},",
		"#{item.courseId},",
		"#{item.liveId},",
		"#{item.nickname},",
		"#{item.chatTime},",
		"#{item.chatType},",
		"#{item.targetUid},",
		"#{item.content},",
		"#{item.createTime},",
		"#{item.updateTime}",
		")",
    "</script>"})

item是傳入實體,getIdentifyTable方法將拿到我們想要的那個表。這裡我們需要明確下$和#的區別:

$是連線,等於是字串的操作,在生成sql語句之前
#是指定引數,是在生成sql語句之後,等於將#指定的引數扔到?中。

所以,這裡用${tableName}而不是#{tableName}

自定義分表

如果看了之前幾篇文章介紹,你可能已經知道如何寫出分表的Mapper了。

這裡我們建立個SimpleShardingMapper,SimpleShardingMapper中定義好我們要實現的CRUD操作,因為是分表,就不要做太多花哨的功能,免得mybatis受不了。

我們可以自定義註解@ShardingKey:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * @author cff
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface ShardingKey {
	String prefix() default "";
	String suffix() default "";
	
	//分表方法
	String methodRange() default "";
	String methodPrecis() default "";
}

methodRange指定處理between and 操作並生成多個表名。

methodPrecis用於指定精確的那個表名。

因為實體可能並不會傳入方法中,所以我們不要建立成員方法,可以建靜態方法。

這樣指定表名的sql生成過程就可以寫成:

ShardingEntity shardingEntity = jpaModelEntity.getShardingEntity();
StringBuilder sql = new StringBuilder();
sql.append("<bind name=\"pattern\" value=\"@");
sql.append(shardingEntity.getEntityFullName());
sql.append("@");
if(isSole){
	sql.append(shardingEntity.getMethodPrecis());
	sql.append("(");
	if(StringUtil.isNotEmpty(paramPrefix)){
		sql.append(paramPrefix);
		sql.append(".");
	}
	sql.append(shardingEntity.getFieldName());
}else{
	sql.append(shardingEntity.getMethodRange());
	sql.append("(");
	sql.append("start, end");
}
sql.append(")\" />");
return sql.toString();

有了表名,我們就可以在組裝sql的時候用${tableName}動態指定了。

如果是多表,那就需要用foreach了
如:

<foreach collection =“pattern” item=“item” index=“index” separator=" union ">

pattern是表名的集合,foreach中間寫查詢語句,用union進行分隔,也可以用union all。

這篇大致介紹完了。

下篇先介紹下JpaMapper的詳細功能和使用方法,後續再增加分頁功能。