注册
【与达梦同行】DM8适配JetBrains_Exposed框架
技术分享/ 文章详情 /

【与达梦同行】DM8适配JetBrains_Exposed框架

卖女孩的小废柴 2022/12/07 2890 3 1

一、背景

近期,用户使用 Kotlin语言的 ORM 框架JetBrains/Exposed框架进行开发需要适配达梦数据库,查看Exposed官网发现原生支持的数据库不包含达梦数据库,随后进行适配操作并进行记录。

image.png

二、软件说明

DM数据库

官网:https://eco.dameng.com/

  1. 达梦数据库作为已商业化的国产数据库代表,在政府及事业单位应用还是比较广泛。
  2. 达梦数据库管理系统是达梦公司推出的具有完全自主知识产权的高性能数据库管理系统,简称DM。达梦数据库管理系统的最新版本是8.0版本,简称DM8。
  3. DM8采用全新的体系架构,在保证大型通用的基础上,针对可靠性、高性能、海量数据处理和安全性做了大量的研发和改进工作,极大提升了达梦数据库产品的性能、可靠性、可扩展性,能同时兼顾OLTP和OLAP请求,从根本上提升了DM8产品的品质。

Kotlin

官网:https://kotlinlang.org/

  1. Kotlin是由JetBrains开发的针对JVM、Android和浏览器的静态编程语言,目前,在Apache组织的许可下已经开源。
  2. 使用Kotlin,开发者可以很方便地开发移动Android应用、服务器程序和JavaScript程序。
  3. Kotlin可以将代码编译成Java字节码,也可以编译成JavaScript,方便在没有JVM的设备上运行。

JetBrains/Exposed

官网:https://www.github.com/JetBrains/Exposed
文档地址:https://www.github.com/JetBrains/Exposed/wiki

  1. Kotlin语言的 ORM 框架Exposed。
  2. Exposed 是一个轻量级 SQL 库,位于 Kotlin 语言的 JDBC 驱动程序之上。Exposed 有两种类型的数据库访问:类型安全的 SQL 包装 DSL 和轻量级数据访问对象 (DAO),可以拥有两个级别的数据库访问权限。
  3. Exposed 可用于模拟各种数据库引擎,帮助您构建不依赖于任何特定数据库引擎的应用程序,并在它们之间进行切换,只需很少或无需更改。

Gradle

官网地址: https://gradle.org/
Gradle 是一款 Google 推出的基于 JVM、通用灵活的项目构建工具,支持 Maven,JCenter 多种第三方仓库;支持传递性
依赖管理、废弃了繁杂的 xml 文件,转而使用简洁的、支持多种语言(例如:java、groovy 等)的 build 脚本文件。

三、项目搭建

1. 环境版本

软件名称 版本号
Gradle 7.4.2
kotlin 1.7.20
JDK 1.8
JetBrains/Exposed 0.40.1
DM8 1-2-114-22.03.04-158322-10045-ENT
jdbc驱动 V8.1.2.138-Build(2022.09.27-13061)

2. 搭建项目

  1. IDEA新建Kotlin项目

image.png

  1. 引入达梦的jar包或新建lib目录

image.png

  1. 标准的jdbc操作
import java.sql.Connection import java.sql.DriverManager import java.sql.SQLException /* CREATE TABLE "SYSDBA"."TEST" ( "ID" VARCHAR(50), "NAME" VARCHAR(50), "SEX" VARCHAR(50)) insert into "TEST"("ID", "NAME", "SEX") VALUES(1, '小伙', '男'); * */ fun main(args: Array<String>) { // 连接数据库 val connection = getConnection() // 预编译 sql 语句 val sql = connection!!.prepareStatement("select * from TEST") // 执行查询 val res = sql.executeQuery() // 遍历结果集并输出数据 while (res.next()) { println("ID -> ${res.getString(1)}") println("姓名 -> ${res.getString(2)}") println("性别 -> ${res.getString(3)}") } } //数据库连接对象 fun getConnection(): Connection? { val driver = "dm.jdbc.driver.DmDriver" val url = "jdbc:dm://127.0.0.1:5236" val username = "SYSDBA" val password = "SYSDBA" try { Class.forName(driver) } catch (e: ClassNotFoundException) { // TODO Auto-generated catch block e.printStackTrace() } var conn: Connection? = null try { conn = DriverManager.getConnection(url, username, password) } catch (e: SQLException) { e.printStackTrace() } return conn }

执行截图
image.png

3. 整合Exposed框架

新增Exposed的相关依赖(build.gradle.kts)

dependencies { testImplementation(kotlin("test")) implementation("org.jetbrains.exposed", "exposed-core", "0.40.1") implementation("org.jetbrains.exposed", "exposed-dao", "0.40.1") implementation("org.jetbrains.exposed", "exposed-jdbc", "0.40.1") // implementation("mysql", "mysql-connector-java", "8.0.11") // implementation("com.oracle.database.jdbc:ojdbc6:11.2.0.4") }

新建dameng_conn.kt

import org.jetbrains.exposed.dao.* import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.IntIdTable import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.vendors.DatabaseDialect import org.jetbrains.exposed.sql.vendors.OracleDialect object Users : IntIdTable() { val name = varchar("name", 50).index() val city = reference("city", Cities) val age = integer("age") } object Cities: IntIdTable() { val name = varchar("name", 50) } class User(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<User>(Users) var name by Users.name var city by City referencedOn Users.city var age by Users.age } class City(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<City>(Cities) var name by Cities.name val users by User referrersOn Users.city } fun main() { Database.connect( "jdbc:dm://127.0.0.1:5236?compatibleMode=oracle", driver = "dm.jdbc.driver.DmDriver", user = "SYSDBA", password = "SYSDBA" ) transaction { addLogger(StdOutSqlLogger) SchemaUtils.create (Cities, Users) val stPete = City.new { name = "St. Petersburg" } val munich = City.new { name = "Munich" } User.new { name = "a" city = stPete age = 5 } User.new { name = "b" city = stPete age = 27 } User.new { name = "c" city = munich age = 42 } println("Cities: ${City.all().joinToString {it.name}}") println("Users in ${stPete.name}: ${stPete.users.joinToString {it.name}}") println("Adults: ${User.find { Users.age greaterEq 18 }.joinToString {it.name}}") } }

执行报错Can’t resolve dialect for connection: jdbc:dm://127.0.0.1:5236

image.png

4. 报错分析

  1. org.jetbrains.exposed.sql.Database.Companion#connect#getDeclaredConstructor 根据url地址去getDeclaredConstructor 取值后为null,顾直接抛异常

image.png

  1. getDialectName函数在dialectMapping中取值并判断前缀

image.png

  1. dialectMapping是Map集合,里面封装的支持的数据库以及前缀。因达梦的url无法识别,无法指定数据库具体的dialectName,顾报错

image.png

5. 解决方案

1. 推荐#方案一(Dm注册到Database)

根据官方的F&A的其他的数据库可实现DatabaseDialect接口并Database.registerDialect()注册进去。
https://www.github.com/JetBrains/Exposed/wiki/FAQ

image.png

/* 解决方案 推荐 注册到Database中*/ Database.registerJdbcDriver("jdbc:dm","dm.jdbc.driver.DmDriver", OracleDialect.dialectName); Database.connect( "jdbc:dm://127.0.0.1:5236?compatibleMode=oracle", driver = "dm.jdbc.driver.DmDriver", user = "SYSDBA", password = "SYSDBA" )

image.png

四、其他

Mysql数据库写法

  1. build.gradle.kts中添加mysql以及相关依赖
dependencies { testImplementation(kotlin("test")) implementation("org.jetbrains.exposed", "exposed-core", "0.40.1") implementation("org.jetbrains.exposed", "exposed-dao", "0.40.1") implementation("org.jetbrains.exposed", "exposed-jdbc", "0.40.1") implementation("mysql", "mysql-connector-java", "8.0.11") }
  1. mysql_conn.kt
import org.jetbrains.exposed.dao.* import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.IntIdTable import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction object Users : IntIdTable() { val name = varchar("name", 50).index() val city = reference("city", Cities) val age = integer("age") } object Cities: IntIdTable() { val name = varchar("name", 50) } class User(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<User>(Users) var name by Users.name var city by City referencedOn Users.city var age by Users.age } class City(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<City>(Cities) var name by Cities.name val users by User referrersOn Users.city } fun main() { // Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver", user = "root", password = "") val connect = Database.connect( "jdbc:mysql://127.0.0.1:3306/dmtest?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false", driver = "com.mysql.cj.jdbc.Driver", user = "root", password = "Gas123." ) transaction { addLogger(StdOutSqlLogger) SchemaUtils.create (Cities, Users) val stPete = City.new { name = "St. Petersburg" } val munich = City.new { name = "Munich" } User.new { name = "a" city = stPete age = 5 } User.new { name = "b" city = stPete age = 27 } User.new { name = "c" city = munich age = 42 } println("Cities: ${City.all().joinToString {it.name}}") println("Users in ${stPete.name}: ${stPete.users.joinToString {it.name}}") println("Adults: ${User.find { Users.age greaterEq 18 }.joinToString {it.name}}") } }

Oracle数据库写法

  1. build.gradle.kts中添加oracle以及相关依赖
dependencies { testImplementation(kotlin("test")) implementation("org.jetbrains.exposed", "exposed-core", "0.40.1") implementation("org.jetbrains.exposed", "exposed-dao", "0.40.1") implementation("org.jetbrains.exposed", "exposed-jdbc", "0.40.1") implementation("com.oracle.database.jdbc:ojdbc6:11.2.0.4") }
  1. oracle_conn.kt
import org.jetbrains.exposed.dao.* import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.IntIdTable import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction object Users : IntIdTable() { val name = varchar("name", 50).index() val city = reference("city", Cities) val age = integer("age") } object Cities: IntIdTable() { val name = varchar("name", 50) } class User(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<User>(Users) var name by Users.name var city by City referencedOn Users.city var age by Users.age } class City(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<City>(Cities) var name by Cities.name val users by User referrersOn Users.city } fun main() { val connect = Database.connect( "jdbc:oracle:thin:@127.0.0.1:1521:oracle", driver = "oracle.jdbc.driver.OracleDriver", user = "scott", password = "oracle" ) transaction { addLogger(StdOutSqlLogger) SchemaUtils.create (Cities, Users) val stPete = City.new { name = "St. Petersburg" } val munich = City.new { name = "Munich" } User.new { name = "a" city = stPete age = 5 } User.new { name = "b" city = stPete age = 27 } User.new { name = "c" city = munich age = 42 } println("Cities: ${City.all().joinToString {it.name}}") println("Users in ${stPete.name}: ${stPete.users.joinToString {it.name}}") println("Adults: ${User.find { Users.age greaterEq 18 }.joinToString {it.name}}") } }

五、代码

链接:https://pan.baidu.com/s/1j9fFXnFnH6_R-C79h6-zSw?pwd=cw01
提取码:cw01

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服