将dao层事务提升到service层

本文介绍了一种在安卓开发中实现跨表事务处理的方法,通过在Service层而非DAO层进行事务管理,确保了数据操作的一致性和原子性。利用ThreadLocal类存储数据库对象,结合自定义的TransactionManager类,实现了事务的开启、执行和回滚。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


title: Service层事务
date: 2018-12-06 00:19:24
tags: 安卓开发

将dao层事务提升到service层

​ dao层就是数据库连接层,service层就是业务层,开发中我们通常将表映射成java对象形式,建立起dao层针对表的增删改查,但dao层的对象一般只针对一个表的操作,在实际开发中我们通常需要一次修改好几张表,比如在班级系统中,如果我删除某个班级,对应的应该删除班级对应的所有学生,可是夸表的操作就需要考虑到同步性,如果删除班级成功,删除学生失败,那么删除班级的操作应该也是撤销的,这需要回滚。

​ 在网上很多教程中要不就是直接在dao层中添加事务,不然就是使用spring框架自动开启事务。可是安卓中没有spring框架,只好手动实现一个了。

​ 首先考虑到事务是在service层实现的,所以我们的数据库对象应当控制在service层中。为了避免不断创建新的数据库对象,我们使用ThreadLocal类给每一个线程储存一个数据库对象,这样可以有效避免资源浪费,也不会造成如单例模式的数据库连接单一而排队产生的等待。

实现思路

创建一个TransactionManager类统一管理事务的开启和关闭,提供回调接口,在service层中创建数据库对象并存入ThreadLocal中,在dao层中从线程中获取数据库对象,这样就可以保证我们在统一线程中获取到的数据库对象是一样的。

class TransactionManager(private val context: Context) {
    private val TAG = TransactionManager::class.java.name
    public fun doTransaction(doTransactionListener: DoTransactionListener ){
        doAsync {
            // 创建数据库对象
            val db = MyDatabaseOpenHelper.writeDb(context)
            db.beginTransaction()
            // 开启事务
            try {
                // 数据库操作
                doTransactionListener.run()
                // 设置事务成功
                db.setTransactionSuccessful()
                uiThread {
                    // 成功回调
                    doTransactionListener.success()
                }
            }catch (e: SQLException){
                e.printStackTrace()
                uiThread {
                    // 失败回调
                    doTransactionListener.error(e)
                }
            }finally {
                // 提交事务
                db.endTransaction()
                db.close()
            }
        }

    }
    interface DoTransactionListener{
        /**
         * 数据库操作
         */
        fun run()
        /**
         * 失败回调
         */
        fun error(e: SQLException)
        /**
         * 成功回调
         */
        fun success()
    }
}
class MyDatabaseOpenHelper(context: Context) : SQLiteOpenHelper(context, DB_NAME,null,1) {
    val TAG = "MyDatabaseOpenHelper"
    companion object {
        // 写 数据库 线程对象
        private val wtol = ThreadLocal<SQLiteDatabase>()
        // 读 数据库 线程对象
        private val rtol = ThreadLocal<SQLiteDatabase>()
        fun writeDb(context: Context): SQLiteDatabase {
            var db = wtol.get()
            Log.v("DBDB"," 获取数据库对象")
            if(db == null) {
                db = MyDatabaseOpenHelper(context).writableDatabase
                wtol.set(db)
                Log.v("DBDB"," 创建数据库写对象")
            }
            return db
        }
        fun readDb(context: Context): SQLiteDatabase {
            var db = rtol.get()
            if(db == null) {
                db = MyDatabaseOpenHelper(context).readableDatabase
                rtol.set(db)
            }
            return db
        }

    }
}
/**
* dao层
*/
class ClassesDaoImpl(private val context: Context) : IClassesDao {
    /**
     * 插入
     * @param obj 班级对象
     * @return
     */
    override fun insert(obj: Classes): Long {
        val writeDatabase = MyDatabaseOpenHelper.writeDb(context)
        val cv = ContentValues()
        cv.put("class_id", obj.classId)
        cv.put("class_name", obj.className)
        cv.put("info", obj.info)
        cv.put("institute", obj.institute)
        cv.put("speciality", obj.speciality)
        cv.put("create_time", obj.createTime)
        return writeDatabase.insert(CLASSES_TABLE, null, cv)
    }
}
/**
* service层
*/
class ClassesServiceImpl(private val context: Context) : IClassesService {
    private val classesDao: IClassesDao = ClassesDaoImpl(context)
    override fun saveClasses(className: String, info: String, institute: String, speciality: String): Classes? {
        val classes = Classes()
        classes.classId = generateRefID()
        classes.className = className
        classes.info = info
        classes.institute = institute
        classes.speciality = speciality
        classes.createTime = getNow()
        val re = classesDao.insert(classes)
        return if (re > 0) {
            classes
        } else null
    }
}

代码中使用

TransactionManager(this).doTransaction(object : TransactionManager.DoTransactionListener{
                    /**
                     * 数据库操作
                     */
                    override fun run() {
                        classesService.deleteClassesByClassId(item.classId)
                    }
                    /**
                     * 失败回调
                     */
                    override fun error(e: android.database.SQLException) {
                       toast("删除失败")
                    }
                    /**
                     * 成功回调
                     */
                    override fun success() {
                        toast("删除成功")
                    }
                })

参考文章:https://blog.youkuaiyun.com/qyy_123456_qyy/article/details/82353257

https://blog.youkuaiyun.com/qq_36115651/article/details/79871813

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值