日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用基于注解的mybatis时,利用反射和注解生成sql语句

發(fā)布時(shí)間:2025/3/21 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用基于注解的mybatis时,利用反射和注解生成sql语句 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在開發(fā)時(shí)遇到一個(gè)問題,在使用基于注解的mybatis插入一個(gè)對象到mysql時(shí),在寫sql語句時(shí)需要列出對象的所有屬性,所以在插入一個(gè)擁有10個(gè)以上屬性的對象時(shí)sql語句就會變得很長,寫起來也很不方便,也很容易拼錯(cuò)。google了一下也沒有找到什么解決方式(可能是姿勢不對),在stackoverflow上提的問題截止目前還沒有人回答。所以自己想了一個(gè)基于反射和注解的解決辦法
git地址:

giraffe0813

spring-mybatis-utils

a555c9?, up-to-date

下面是之前的代碼片段:

1 2 3 @Insert("insert into poi_shop(name,brand,tags,status,phone,mobile,business_time,address,city,lng,lat,business_type,attribute_json) values(#{name},#{brand},#{tags},#{status},#{phone},#{mobile},#{business_time},#{address},#{city},#{lng},#{lat},#{business_type},#{attribute_json})") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") public Long insertPoiInfo(PoiBo poiBo);

第一版(利用反射)

首先想到的是可以利用反射獲得對象的所有屬性,然后拼接成sql語句。所以寫了一個(gè)基于反射拼裝sql語句的方法,然后基于mybatis動態(tài)獲得sql語句的方式 獲得完整的sql 具體的代碼如下:
接口層改為下面的樣子,sql語句的生成放到PoiSqlProvider的insertPoiBo方法中

1 2 @InsertProvider(type = PoiSqlProvider.class, method = "insertPoiBo") public Long insertPoiInfo(@Param("poiBo")PoiBo poiBo);

PoiSqlProvider.class

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ??public String insertPoiBo(Map<String,Object> map){ ???????PoiBo poiBo = (PoiBo)map.get("poiBo"); ???????StringBuilder sql = new StringBuilder("insert into poi_shop "); ???????//get sql via reflection ???????Map<String,String> sqlMap = getAllPropertiesForSql(poiBo, "poiBo"); ???????// ???????sql.append(sqlMap.get("field")).append(sqlMap.get("value")); ???????System.out.println(sql.toString()); ???????return sql.toString(); ???} //根據(jù)傳入的對象 基于反射生成兩部分sql語句 ???private? Map<String,String> getAllPropertiesForSql(Object obj, String objName){ ???????Map<String,String> map = new HashMap<String,String>(); ????????if(null == obj) return map; ???????StringBuilder filedSql = new StringBuilder("("); ???????StringBuilder valueSql = new StringBuilder("value ("); ???????Field[] fields = obj.getClass().getDeclaredFields(); ???????for (int i = 0; i < fields.length; i++) { ???????????filedSql.append(fields[i].getName() + ","); ???????????valueSql.append("#{" + objName + "." + fields[i].getName() + "},"); ???????} ???????//remove last ',' ???????valueSql.deleteCharAt(valueSql.length() - 1); ???????filedSql.deleteCharAt(filedSql.length() - 1); ???????valueSql.append(") "); ???????filedSql.append(") "); ???????map.put("field",filedSql.toString()); ???????map.put("value", valueSql.toString()); ???????System.out.println("database filed sql: " + filedSql.toString()); ???????System.out.println("value sql:" + valueSql.toString()); ???????return map; ???}

下面是基于反射生成的兩部分sq語句和最后拼接的語句

1 2 3 4 5 6 7 8 9 database filed sql: (id,name,brand,tags,status,phone,mobile,business_time,address,city,lng,lat,business_type,attribute_json,updated_at,created_at) value sql: value(#{poiBo.id},#{poiBo.name},#{poiBo.brand},#{poiBo.tags},#{poiBo.status},#{poiBo.phone},#{poiBo.mobile},#{poiBo.business_time},#{poiBo.address},#{poiBo.city},#{poiBo.lng},#{poiBo.lat},#{poiBo.business_type},#{poiBo.attribute_json},#{poiBo.updated_at},#{poiBo.created_at}) insert into poi_shop (id,name,brand,tags,status,phone,mobile,business_time,address,city,lng,lat,business_type,attribute_json,updated_at,created_at) value (#{poiBo.id},#{poiBo.name},#{poiBo.brand},#{poiBo.tags},#{poiBo.status},#{poiBo.phone},#{poiBo.mobile},#{poiBo.business_time},#{poiBo.address},#{poiBo.city},#{poiBo.lng},#{poiBo.lat},#{poiBo.business_type},#{poiBo.attribute_json},#{poiBo.updated_at},#{poiBo.created_at})

要注意的是如果數(shù)據(jù)庫的字段名和插入對象的屬性名不一致,那么不能使用生成的database filed sql。

最終版(加入注解)

上面的getAllPropertiesForSql方法有個(gè)缺點(diǎn),如果數(shù)據(jù)庫的字段名和類的屬性名不一致,就不能依靠反射獲得sql了。所以借鑒老大的ORM框架也寫了一個(gè)注解Column,用于model類的屬性上,表明屬性所對應(yīng)數(shù)據(jù)庫字段。下面是Column注解的snippet。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /* 定義字段的注解*/ @Retention(RetentionPolicy.RUNTIME) /*該注解只能用在成員變量上*/ @Target(ElementType.FIELD) public @interface Column { ????/** ?????* 用來存放字段的名字 如果未指定列名,默認(rèn)列名使用成員變量名 ?????* ?????* @return ?????*/ ????String name() default ""; ????}

之后在model類屬性上加入對應(yīng)的注解,省略getter和setter。Column的name為空時(shí),代表屬性名和字段名一致。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class PoiBo { ????@Column ????private Long id; ????@Column(name = "poi_name") ????private String name;//表示name屬性對應(yīng)數(shù)據(jù)庫poi_name字段 ????@Column(name = "poi_brand") ????private String brand;//表示brand屬性對應(yīng)數(shù)據(jù)庫poi_brand字段 ????@Column ????private String tags; ????@Column ????private Integer status; ????@Column ????private String phone; ????@Column ????private String mobile; ????@Column ????private String business_time; ????@Column ????private Float average_price; ????@Column ????private String address; ????@Column ????private String city; ????@Column ????private Double lng; ????@Column ????private Double lat; ????@Column ????private String business_type; ????@Column ????private String attribute_json; ????@Column ????private Timestamp updated_at; ????@Column ????private Timestamp created_at; ????}

修改getAllPropertiesForSql方法,通過獲取類屬性上的注解獲得數(shù)據(jù)庫字段名。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 private? Map<String,String> getAllPropertiesForSql(Object obj, String objName){ ????????Map<String,String> map = new HashMap<String,String>(); ?????????if(null == obj) return map; ????????StringBuilder filedSql = new StringBuilder("("); ????????StringBuilder valueSql = new StringBuilder("value ("); ????????Field[] fields = obj.getClass().getDeclaredFields(); ????????for (Field field : fields) { ????????????????// 判斷該成員變量上是不是存在Column類型的注解 ????????????????if (!field.isAnnotationPresent(Column.class)) { ????????????????????continue; ????????????????} ????????????????Column c = field.getAnnotation(Column.class);// 獲取實(shí)例 ????????????????// 獲取元素值 ????????????????String columnName = c.name(); ????????????????// 如果未指定列名,默認(rèn)列名使用成員變量名 ????????????????if ("".equals(columnName.trim())) { ????????????????????columnName = field.getName(); ????????????????} ????????????filedSql.append(columnName + ","); ????????????valueSql.append("#{" + objName + "." + field.getName() + "},"); ????????} ????????//remove last ',' ????????valueSql.deleteCharAt(valueSql.length() - 1); ????????filedSql.deleteCharAt(filedSql.length() - 1); ????????valueSql.append(") "); ????????filedSql.append(") "); ????????map.put("field",filedSql.toString()); ????????map.put("value", valueSql.toString()); ????????System.out.println("database filed sql: " + filedSql.toString()); ????????System.out.println("value sql:" + valueSql.toString()); ????????return map; ????}

利用反射+注解之后的輸出結(jié)果,可以看到sql語句正確按照name的Column注解的輸出了name屬性對應(yīng)的數(shù)據(jù)庫字段是poi_name.

1 2 3 4 5 6 7 8 9 database filed sql: (id,poi_name,poi_brand,tags,status,phone,mobile,business_time,average_price,address,city,lng,lat,business_type,attribute_json,updated_at,created_at) value sql: value(#{poiBo.id},#{poiBo.name},#{poiBo.brand},#{poiBo.tags},#{poiBo.status},#{poiBo.phone},#{poiBo.mobile},#{poiBo.business_time},#{poiBo.average_price},#{poiBo.address},#{poiBo.city},#{poiBo.lng},#{poiBo.lat},#{poiBo.business_type},#{poiBo.attribute_json},#{poiBo.updated_at},#{poiBo.created_at}) insert into poi_shop (id,poi_name,poi_brand,tags,status,phone,mobile,business_time,average_price,address,city,lng,lat,business_type,attribute_json,updated_at,created_at) value (#{poiBo.id},#{poiBo.name},#{poiBo.brand},#{poiBo.tags},#{poiBo.status},#{poiBo.phone},#{poiBo.mobile},#{poiBo.business_time},#{poiBo.average_price},#{poiBo.address},#{poiBo.city},#{poiBo.lng},#{poiBo.lat},#{poiBo.business_type},#{poiBo.attribute_json},#{poiBo.updated_at},#{poiBo.created_at})

原文出處:?Giraffe from:?http://www.importnew.com/22918.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的使用基于注解的mybatis时,利用反射和注解生成sql语句的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。