mybatis免sql外掛之JpaMapper-以Jpa hibernate的風格寫mybatis(mybatis實現簡單分表-sharding功能)
mybatis免sql外掛之JpaMapper-以Jpa hibernate的風格寫mybatis(mybatis實現簡單分表-sharding功能)
簡介
JpaMapper以Jpa hibernate的風格寫mybatis的程式碼,可以減少手動寫sql的煩惱。
優勢:
- 不替換底層實現,僅生成sql並交給mybatis
- 方法基本與Jpa hibernate相似,易於框架替換,當然,沒那麼厲害,不支援聯表哦,專案還在繼續完善中。
- 提供簡單分表功能
- 邏輯簡單,可以拿去自己定製
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的類主要有三個:
- Jdbc3KeyGenerator,其實就是自增策略
- NoKeyGenerator,顧名思義就是啥也沒有。
- 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的詳細功能和使用方法,後續再增加分頁功能。