Druid+Sqlite-JDBC+Kotlin,封装的一个都是毛病的工具类,奆佬们,评论区教一下我怎么封装

这是一个关于Kotlin语言中如何使用Druid连接池与SQLite-JDBC的工具类实现,包括单例模式、数据库连接、SQL操作的方法。代码示例展示了如何初始化Druid数据源,执行增删改查操作,以及如何处理结果集。同时,也提供了一个SQLiteUtils类作为对比,展示不同的数据库操作方式。
摘要由CSDN通过智能技术生成

Druid+JDBC工具类
我只是一个新手,也不怎么会kotlin但是我看教程都很少,讲SQLite-JDBC结合Druid或者说怎么写Durid的配置文件,

我先放工具类

import com.alibaba.druid.pool.DruidDataSourceFactory
import java.io.FileInputStream
import java.io.InputStream
import java.lang.reflect.Constructor
import java.lang.reflect.Field
import java.sql.*
import java.util.*
import javax.sql.DataSource

class JdbcUtil {

    //数据源连接池对象
    private var dataSource: DataSource? = null

    //ThreadLocal 对象
    private var threadLocal: ThreadLocal<Connection>? = null

    private constructor() {
        try {
            val inputStream: InputStream = FileInputStream("db.properties")
            val prop: Properties = Properties()
            prop.load(inputStream)

            //使用Druid连接池方式
            dataSource = DruidDataSourceFactory.createDataSource(prop)
            threadLocal = ThreadLocal()

        } catch (e: Exception) {
            throw RuntimeException("加载配置文件出错!${e.message}")
        }

    }

    @Throws(SQLException::class)
    fun getConnection(): Connection? {
        //从当前线程获取Connection
        var connection: Connection? = this.threadLocal!!.get()
        if (connection == null) {
            //如果没有就从连接池获取
            connection = dataSource?.connection
            //添加到ThreadLocal
            this.threadLocal?.set(connection)
        }
        return connection
    }


    companion object {
        @Volatile
        private var instance: JdbcUtil? = null

        fun getInstance() = instance ?: synchronized(this) {
            instance ?: JdbcUtil().also { instance = it }
        }
    }

    /**
     * 封装的通用增删改方法
     * @param sql 需要操作的SQL语句
     * @param params 执行SQL语句时需要的参数
     */
    private fun update(sql: String, vararg params: Any = emptyArray()): Int {
        var connection: Connection? = null
        var statement: PreparedStatement? = null

        try {
            connection = getConnection()
            statement = connection?.prepareStatement(sql)

            if (params.isNotEmpty()) {
                for (i in params.indices) {
                    statement?.setObject(i + 1, params[i])
                }
            }
            return statement!!.executeUpdate()
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            destroy(connection, statement, null)
        }
        return 0
    }

    fun executeUpdate(sql: String): Int {
        return update(sql)
    }

    fun executeUpdateBoolean(sql: String): Boolean {
        val result: Int = update(sql)
        if (result > 0) {
            return true
        }
        return false
    }

    fun executeUpdate(sql: String, vararg params: Any): Int {
        return update(sql, params)
    }

    fun getPreparedStatement(sql: String): PreparedStatement {
        return getConnection()!!.prepareStatement(sql)
    }

    fun executeUpdateBoolean(sql: String, vararg params: Any): Boolean {
        val result: Int = update(sql, params)
        if (result > 0) {
            return true
        }
        return false
    }

    /**
     * 查询多条数据的封装方法
     * @param clazz 结果的封装对象
     * @param sql 要执行的SQL语句
     * @param params 执行SQL语句时需要的参数
     * @param <T> 消费金融泛型类型
     * @return 返回查询的结果集
     */
    fun <T> query(sql: String, clazz: Class<T>, vararg params: Any): List<T> {
        var connection: Connection? = null
        var statement: PreparedStatement? = null
        var rs: ResultSet? = null
        var entities: List<T>?

        try {
            connection = getConnection()
            statement = connection!!.prepareStatement(sql)
            for (i in params.indices) {
                statement?.setObject(i + 1, params[i])
            }
            rs = statement.executeQuery()
            entities = mutableListOf()

            //获取ResultSet对象来获取元数据信息
            val meteData: ResultSetMetaData = rs.metaData
            val columnCount: Int = meteData.columnCount

            while (rs.next()) {
                val entity: T = clazz.getDeclaredConstructor().newInstance()
                for (i in 1..columnCount) {
                    val columnLabel: String = meteData.getColumnLabel(i)
                    val field: Field = clazz.getDeclaredField(columnLabel)
                    field.isAccessible = true
                    field.set(entity, rs.getObject(columnLabel))
                }
                entities.add(entity)
            }
            return entities
        } catch (e: Exception) {
            e.printStackTrace()
            throw RuntimeException("查询多条数据时出错,错误信息为:${e.message}")
        } finally {
            destroy(connection, statement, rs)
        }
    }

//                entity = if (clazz == Int::class.java) {
//                    val constructor: Constructor<T> = clazz.getDeclaredConstructor(Int::class.javaPrimitiveType)
//                    constructor.newInstance(rs.getInt(1))
//                } else if (clazz == Long::class.java) {
//                    val constructor: Constructor<T> = clazz.getDeclaredConstructor(Long::class.javaPrimitiveType)
//                    constructor.newInstance(rs.getLong(1))
//                } else {
//                    throw RuntimeException("参数中能传 int 类型或 long 类型。")
//                }

    /**
     * 查询多条数据的封装方法
     * @param clazz 结果的封装对象
     * @param sql 要执行的SQL语句
     * @param params 执行SQL语句时需要的参数
     * @param <T> 消费金融泛型类型
     * @return 返回查询的结果
    </T> */
    fun <T> queryForObject(clazz: Class<T>, sql: String?, vararg params: Any?): T? {
        var conn: Connection? = null
        var pstm: PreparedStatement? = null
        var rs: ResultSet? = null
        var entity: T? = null
        try {
            conn = getConnection()
            pstm = conn!!.prepareStatement(sql)
            for (i in params.indices) {
                pstm.setObject(i + 1, params[i])
            }
            rs = pstm.executeQuery()
            val metaData: ResultSetMetaData = rs.metaData
            while (rs.next()) {
                entity = when (clazz) {
                    Int::class -> {
                        val constructor: Constructor<T> = clazz.getDeclaredConstructor(Int::class.java)
                        constructor.newInstance(rs.getInt(1))
                    }
                    Long::class -> {
                        val constructor: Constructor<T> = clazz.getDeclaredConstructor(Long::class.java)
                        constructor.newInstance(rs.getLong(1))
                    }
                    else -> {
                        throw RuntimeException("参数可以转换int或者long")
                    }
                }
            }
            return entity
        } catch (e: Exception) {
            e.printStackTrace()
            throw RuntimeException("统计查询时出错,错误信息为:" + e.message)
        } finally {
            destroy(conn, pstm, rs)
        }
    }


    private fun destroy(connection: Connection?, statement: PreparedStatement?, rs: ResultSet?) {
        connection?.close()
        statement?.close()
        rs?.close()
    }


}

这两个随便借鉴,我都感觉有问题,我太菜了

import java.io.File
import java.io.FileInputStream
import java.lang.reflect.Field
import java.net.URL
import java.sql.*
import java.util.*
import kotlin.collections.ArrayList


class SQLiteUtils {

    //磁盘文件路劲名 db
    private var path: String? = null

    // 操作链接
    private var connection: Connection? = null

    //语法执行层
    private var statement: Statement? = null

    //连接数据库的信息
    private var user = ""
    private var password = ""
    private var url = ""
    private var driver = ""

    private constructor(path: String) {
        this.path = path
        connection = getConnection(path)

    }


    /**
     * 把JDBC返回的结果集封装成特定类型
     * @Author: fangju
     * @Date: 2019/6/15
     */
    interface IResultSetHandler<T> {
        @Throws(Exception::class)
        fun handle(rs: ResultSet): T?
    }


    //Kotlin 可带参数的检测锁模式
    companion object {
        @Volatile
        private var instance: SQLiteUtils? = null

        fun getInstance(path: String) = instance ?: synchronized(this) {
            instance ?: SQLiteUtils(path).also { instance = it }
        }
    }


    @Throws(SQLException::class)
    fun getStatement(): Statement? {
        if (this.statement == null) {
            this.statement = this.connection!!.createStatement()
        }
        return this.statement
    }

    /**
     * 获取Sqlite操作链接
     *
     * @param path sqlite数据表,为磁盘文件名
     * @return
     */
    @Throws(SQLException::class, ClassNotFoundException::class)
    private fun getConnection(path: String?): Connection? {
        var connection: Connection? = null
        Class.forName("org.sqlite.JDBC")
        if (path!!.endsWith(".db")) {
            connection = DriverManager.getConnection("jdbc:sqlite:$path")
        }
        return connection
    }

    /**
     * 增删改操作
     * @param sql 传入的SQL语句
     * @param params 可变参数
     * @return 操作结果
     */
    /* 在kotlin变长参数中 * 叫 spread操作,可以理解为“打散”,“分散”*/
    fun executeUpdate(sql: String, vararg params: Any): Int {
        var preparedStatement: PreparedStatement? = null
        var result: Int = 0
        try {
            preparedStatement = connection?.prepareStatement(sql)
            //给预编译语句赋值
            for (i in params.indices) {
                preparedStatement?.setObject(i + 1, params[i])
            }
            //执行SQL语句,获取执行结果
            result = preparedStatement!!.executeUpdate()

        } catch (e: SQLException) {
            e.printStackTrace()
        } finally {
            preparedStatement?.close()
        }
        return result
    }

    fun <T> executeQuery(sql: String, handler: IResultSetHandler<T>, vararg params: Any): T? {
        var preparedStatement: PreparedStatement? = null
        var rs: ResultSet? = null
        var connection: Connection? = null
        try {
            connection = this.connection
            preparedStatement = connection?.prepareStatement(sql)
            for (i in params.indices) {
                preparedStatement!!.setObject(i + 1, params[i])
            }
            rs = preparedStatement!!.executeQuery()
            return handler.handle(rs)
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            preparedStatement?.close()
            rs?.close()
            connection?.close()
        }
        return null
    }


    fun executeDML(sql: String, vararg params: Any): Boolean {
        var connection: Connection? = null
        var statement: PreparedStatement? = null
        try {
            connection = getConnection(path)

            statement = connection?.prepareStatement(sql)
            for (i in params.indices) {
                statement?.setObject(i + 1, params[i])
            }
            val resultCode: Int = statement!!.executeUpdate()
            if (resultCode > 0) {
                return true
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            connection?.close()
            statement?.close()
        }
        return false
    }


    //获取连接的方法
    private fun getConnection(): Connection? {
        var connection: Connection? = null
        try {
        //通过反射获取配置文件位置
            val resource: URL? = SQLiteUtils::class.java.getResource("/")
            val filePath = File(resource!!.file)
            val files: Array<File> = filePath.listFiles()
            var configFile: File? = null //配置文件路径
            for (file in files) {
                if (!file.isDirectory) //不是文件夹
                {
                    if (file.name.equals("mysql.properties")) //文件名为mysql.properties
                    {
                        configFile = File(file.path) //确定配置文件
                    }
                }
            }
            if (configFile == null) { //如果没有mysql.properties配置文件就抛出异常
                throw java.lang.Exception("小老弟,检查检查配置文件mysql.properties有没有")
            }
            //        通过Properties读取配置文件
            val properties = Properties()
            properties.load(FileInputStream(configFile))
            //        获取连接数据库的信息
            user = properties.getProperty("user")
            password = properties.getProperty("password")
            url = properties.getProperty("url")
            driver = properties.getProperty("driver")

            // 获取数据库连接
            Class.forName(driver) //加载驱动
            connection = DriverManager.getConnection(url, user, password)
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        }
        return connection
    }

    /**
     * 通用的查询方法
     *
     * @param sql    要执行的sql语句
     * @param clazz  对应的实体类
     * @param params 条件参数(?对应的值)
     * @param <T>    对应的实体类型
     * @return
    </T> */
    //    T表示集合中使用的泛型,Class<T> clazz就是对应的实体类
    fun <T> executeDQL(sql: String?, clazz: Class<T>, vararg params: Any?): List<T>? {
        var connection: Connection? = null
        //PreparedStatement 是 Statement 的子类,它的一大好处是可以防止 SQL 注入
        var statement: PreparedStatement? = null
        var resultSet: ResultSet? = null
        var list: List<T>? = null //存放实体类的集合
        try {
            connection = getConnection() //获取连接
            statement = connection!!.prepareStatement(sql) //执行sql语句
            //            设置参数,如果params不为空说明要设置参数
            for (i in params.indices) {
                //从第一位开始对应赋值
                statement.setObject(i + 1, params[i])
            }
            resultSet = statement.executeQuery() //获取结果集
            //        可以通过ResultSet获取当前有那些列
            val metaData = resultSet.metaData //元数据,可以通过它获取表中的列
            //        获取表中列的总数
            val columnCount = metaData.columnCount
            //            用来存放我们查询的信息对应的实体类
            list = ArrayList()
            //判断是否有记录,然后再根据列名获取每列的信息
            while (resultSet.next()) { //每次循环获取的是一列数据
                //我们现在不能确定传入的实体类,这里用泛型替代,当你传入实体类型时确定
                val t = clazz.getDeclaredConstructor().newInstance()
                for (i in 1..columnCount)  //循环要从1开始
                { //遍历列数,获取每一列的名字
                    val columnLabel = metaData.getColumnLabel(i) //列名
                    //                通过列名获取对应列的数据
                    val `object` = resultSet.getObject(columnLabel)
                    //                    通过列名获取实体类中的属性名
                    val field: Field = clazz.getDeclaredField(columnLabel)
                    //                    给获取的实体类的属性赋值
                    field.isAccessible = true //取消安全检查
                    field.set(t, `object`) //给t对象设置从数据库中查询出来的object值
                    field.isAccessible = false //开启安全检查
                }
                list.add(t) //把得到的实体类存入集合
            }
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        } finally {
            //关闭连接
            close(connection, statement, resultSet)
        }
        return list //返回实体类集合
    }

    private fun close(connection: Connection?, statement: Statement?, resultSet: ResultSet?) {
        try {
            connection?.close()
            statement?.close()
            resultSet?.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }


    @Throws(SQLException::class)
    fun executeUpdate(sql: String) {
        getStatement()?.executeUpdate(sql)
    }

    @Throws(SQLException::class)
    private fun releaseConnection() {
        if (this.connection != null || this.connection!!.isClosed) {
            this.connection!!.close()
            this.connection = null
        }

        if (this.statement != null) {
            this.statement!!.close()
            this.statement = null
        }

    }

}

我是在网上找大佬写的,我只是把代码转成kotlin并改成了单例模式,我也很少写文章,懒。不能保证这个工具类有没有问题,我对kotlin的反射还不是很了解,希望大家可以评论区留言,

db.properties


druid.driverClassName=org.sqlite.JDBC
druid.url=jdbc:sqlite:test.db
druid.validationQuery=SELECT 1
druid.testWhileIdle=true
druid.testOnBorrow=false
druid.testOnReturn=false

如上配置之后,运行项目idea终端会抛出

510, 2022 6:43:09 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited

百度了一圈,没什么解决办法,
反正项目运行之后会在C:\Users\WuXiangGuJun\IdeaProjects\SQLite-JDBC\test.db

在这里插入图片描述
在idea中双击test.db可以打开数据库文件

在这里插入图片描述这是刚刚创建的数据库,当然这些列是我自己搞的

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值