使用基于Mybatis注解,利用反射和注解生成SQL语句
来源:互联网 发布:淘宝联盟可以赚钱吗 编辑:程序博客网 时间:2024/06/09 22:02
今天是手伤后的第3天,感谢大家的关心!缴了6针现伤口已经愈合不疼了,但今天依然还是坚持写博客。。。好了,不说废话,正式进入今天的话题:
我们在使用SSM整合开发的时候,常会遇到这样一个问题(在这里以我平时做项目遇到的问题来说:Maven项目、数据库采用的mysql5.7.16):使用注解的mybatis插入一个对象到mysql中,在写sql语句时需要列出对象的所有属性,如果要插入一个10个以及多个以上属性的对象时sql语句会变得越来越长,写起来也就很不方便,也很容易拼错。因此,上网搜索了一下,也有关于这方面注解的博客文章,我们可以利用反射和注解来解决这个问题,因此我学习了它,并且总结…到我自己的博客和感兴趣的朋友们一起学习和分享!
下面我们来看一段代码片段,如下(嘿嘿,这是我粘贴的人家的代码片):
@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语句:
第一、利用反射:
首先想到的是可以利用反射获得对象的所有属性,然后拼接成sql语句。所以写了一个基于反射拼装sql语句的方法,然后基于mybatis动态获得sql语句的方式 获得完整的sql具体的代码如下:
接口层改为下面的样子,sql语句的生成放到PoiSqlProvider的insertPoiBo方法中@InsertProvider(type = PoiSqlProvider.class, method = "insertPoiBo")public Long insertPoiInfo(@Param("poiBo")PoiBo poiBo);
我们来看一下PoiSqlProvider.java的代码:
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(); } //根据传入的对象 基于反射生成两部分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() + "},"); } 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语句和最后拼接的语句:
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})
我们需要注意的是如果数据库的字段名和插入对象的属性名不一致,那么不能使用生成的database filed sql。
第二、利用注解:
上面的getAllPropertiesForSql方法有个缺点,如果数据库的字段名和类的属性名不一致,就不能依靠反射获得sql了。所以借鉴老大的ORM框架也写了一个注解Column,用于model类的属性上,表明属性所对应数据库字段。下面是Column注解的snippet。如下代码:
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 { /** * 用来存放字段的名字 如果未指定列名,默认列名使用成员变量名 * * @return */ String name() default "";}
之后在model类属性上加入对应的注解,省略getter和setter。Column的name为空时,代表属性名和字段名一致。如下代码:
public class PoiBo { @Column private Long id; @Column(name = "poi_name") //表示name属性对应数据库poi_name字段 private String name; @Column(name = "poi_brand") //表示brand属性对应数据库poi_brand字段 private String 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方法,通过获取类属性上的注解获得数据库字段名。如下代码:
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);// 获取实例 // 获取元素值 String columnName = c.name(); // 如果未指定列名,默认列名使用成员变量名 if ("".equals(columnName.trim())) { columnName = field.getName(); } filedSql.append(columnName + ","); valueSql.append("#{" + objName + "." + field.getName() + "},"); } 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;}
利用反射+注解之后的输出结果,可以看到sql语句正确按照name的Column注解的输出了name属性对应的数据库字段是poi_name。如下:
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})
写完了试试吧,总之,总这种方法,利用反射和注解生成的SQL语句还是很方便的。
GOOD LUCK!
- 使用基于注解的mybatis时,利用反射和注解生成sql语句
- 使用基于Mybatis注解,利用反射和注解生成SQL语句
- Mybatis基于注解形式的sql语句生成
- 使用基于注解的mybatis实现根据参数动态生成sql语句
- 通过反射+注解生成sql语句
- Mybatis基于注解的sql语句
- 使用Java反射(Reflect)、自定义注解(Customer Annotation)生成简单SQL语句
- Mybatis基于注解结合Java编写Sql语句进行CRUD
- Java注解(Annotation)详解(四)——注解反射生成SQL语句
- Java注解(Annotation)详解(四)——注解反射生成SQL语句
- Java注解(Annotation)详解(四)——注解反射生成SQL语句
- 利用注解动态生成sql
- Mybatis SQL映射语句中参数注解使用规则
- 利用注解反射生成导出excel文件
- 使用自定义注解生成简单查询sql语句
- MyBatis注解应用之动态SQL语句
- MyBatis SQL语句参数注解详释
- Mybatis增强型注解简化SQL语句
- 蓝牙音频传输格式:ACC,SBC,APTX和LDAC
- 折腾一下框架请求的姿势
- 数据结构——用python实现排序算法
- 学习安卓时犯下的错误总结(持续更新ing)
- 感知机的收敛性(Novikoff定理)证明(原创)
- 使用基于Mybatis注解,利用反射和注解生成SQL语句
- 《算法概论》习题8.3
- 微信公众平台测试号
- mysql所有表查询
- 内存溢出WAS生成的文件javacore.***.txt 、heapdump.***.phd、core.***.dmp、Snap.***.trc说明
- 可做的题
- 2016 小灶练习 E (HDU1263)
- 《java web 学习笔记三》:CSS
- 接口和内部类