简易DAO层 设计

dao层即数据持久层,作为一个中间组件,承接上文的Model数据,将其转换成sql语言,并且插入数据库里面。本文将根据dao层的设计思路,将基于对vertx的数据持久进行简单的封装。设计思路参考(hibernate)

1. 数据Model

在Dao层每一张表对应一个bean model,通过一些注解找到相应的数据表的信息,例如一般而已,可以定义

annotation class TableName(val value : String)  // 标记数据库表

@Target(AnnotationTarget.FIELD) // 标记字段
annotation class Column(val name:String)

在bean model 里面用这两个注解,使得字段与表明一一映射开来。例如:

@TableName("person")
data class PersonModel(
    var id:Int,
    var name:String,
    @Column("address")
    var myAddress:String,
)

上面这个数据model对于数据库里面的表 person ,字段为

 id -> id,
 name -> name,
 myAddress -> address

2. model反射

通过上面的model数据映射,主要是获取每个数据库里面的字段名,以及映射类型,还有就是model属性名,因此按照这个思路来解析上述的model为:

val clazz = PersonModel::class.java
val fields =  clazz.declaredFields.toList().filter { !it.annotations.toList()
        .map {
            val column = it.getAnnotation(Column::class.java)
            // 数据库字段名 类型 model字段名 
            if (column == null) it.name join  typeConversion(it.type) join it.name
            else column.name join typeConversion(it.type) join it.name
        }

可以发现fields 是包含的数据字段的基本信息,因此可以很容易构建出sql语句

3. sql语句构建

insert:

  var sql = fields.joinToString(prefix = "insert into $name (",postfix = ")"){ "`${it.first}`" }
   sql += fields.joinToString(prefix = " values(",postfix = ")") {"?"}

select:

var sql = fields.joinToString(prefix="select",postfix="from $tableName"){ "`${it.first}`" }

delete:

val sql = "delete from $tableName where id = ?"

update:

  val model = JsonObject()
  val map = model.map.filter { it.key != "id" }.filter { fields.map { map -> map.first }.contains(it.key) }.map { it.key join it.value }.toList()
  val sql = map.joinToString(prefix = "update $name set ",postfix = " where id = ${model.getString("id")}") { "`${it.first}` = ? " }

通过上面的sql语句构建基本可以构建出CURD常用的sql语句

4、查询结果映射

通过上述的select sql语句,可以实现一个表的结果查询结果,但是一般而言,通过JDBC的返回的结果是ResultSet结果集。这里还是用vertx距离,通过上述sql语句返回的是RowSet< Row>结果集,有了上述的field很容易就可以映射出结果集,如下:

val result:RowSet
val ret = result.map { row -> 
fields.associate {
      if (it.first == it.third) it.first join row.get(it.second, it.first)
      else it.third join row.get(it.second, it.first)
}

返回的结果即是List< Map > 每个map即是但是你所定义的model 当然你也可以把map 转换成实体类,通过GSON转化成json字符串,在通过json字符串转换成model对象,如下:

ret.map { it.toJson().toObj(clazz) }

5. 外键关联设计

通过上述方案简单的CURD已经可以实现,但数据库里面比较重要还有外键关联查询,也就是一对一,以及一对多,多对多的关联查询。因此同样是从model出发,添加注解

@Target(AnnotationTarget.FIELD)
// model 表示要关联的model localKey 表示当前model的外键 key,foreignKey表示关联model的key
annotation class ForeignKey(val model:String, val localKey:String, val foreignKey:String)

构建外键的 flied:

 val foreignField = clazz.declaredFields.toList().filter { it.annotations.toList().map { it.annotationClass }.contains(ForeignKey::class) }

构建外键查询的sql(即构建查询join sql语句):

       var select  = fields.joinToString(prefix="select "){ "$name.${it.first} as ${name}_${it.first}" }
       val from = " from $name $name "
       val join = foreignField.map { it.getAnnotation(ForeignKey::class.java) }.map { selectSQL(it,name) }.toList()
       if(join.isNotEmpty())  select += ","
       var sql =  join.joinToString(prefix=select,postfix = from) { it.first }
       sql += join.joinToString("") { it.second }

而同样通过结果映射可以将结果映射出来:

            val primaryData = fields.associate { field -> field.third join row.get(field.second, "${name}_${field.first}") }
            val primaryJson = JsonObject(primaryData)
            foreignField.forEach { foreign ->
                val foreignKeyJson = parserForeignKeyData(foreign.getAnnotation(ForeignKey::class.java),name,row)
                primaryJson.put(foreignKeyJson.first,foreignKeyJson.second.map)
            }
           primaryJson.map

同样通过GSON的序列化,可以将map转换成实体对象也如上面所述。

总结

本文实现了一个简单的dao层,对其简单的CURD有了实现,并且也对外键操作有了一定实现,相比传统的Hibernate,以及MyBaits来说,在一些小项目上没有必要引入那么框架,至今用单纯的JDBC 连接即可。本文即是介绍一种简单dao层的实现思路

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

myenjoy_1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值