如何从缓存中逐出对象之前更新数据库中的对象?

时间:2019-10-06 12:43:43

标签: kotlin ehcache ktor kotlin-exposed

在我的ktor网络应用中,我正在使用exposed sql将对象存储在数据库中。

我还使用ehcache将一些工作从数据库转移到缓存中。

我希望能够更新缓存中的对象,而不必同时更新数据库中的对象(因为它会经常发生)。

我担心的是,当从缓存中逐出对象时,所做的更改将不会保存在数据库中

如何保存对对象所做的更改而不必每次都访问数据库?

MyObject.kt

import kotlinx.css.Color
import java.io.Serializable

data class MyObject(val ID: Int, val userID: String, var description: String, var color: Color, var count: Long = 0) : Serializable

MyObjects.kt

import org.jetbrains.exposed.sql.Table

object MyObjects : Table() {
    val ID = integer("ID").primaryKey().autoIncrement()
    val count = long("Count")
    val userID = varchar("UserID", 64).index()
    val color = varchar("Color", 16)
    val description = varchar("Description", 128)
}

DAOFacade.kt

import kotlinx.css.Color
import kotlinx.io.core.Closeable

interface DAOFacade : Closeable {
    fun getMyObject(ID: Int): MyObject?
    fun updateMyObject(ID: Int, description: String? = null, color: Color? = null, count: Long? = null)
}

DAOFacadeDatabase.kt

import kotlinx.css.Color
import org.jetbrains.exposed.sql.*

class DAOFacadeDatabase(private val DB: Database = Database.Companion.connect("jdbc:h2:mem:test", "org.h2.Driver")) : DAOFacade {
    init {
        DB.transaction { create(MyObjects) }
    }

    private fun ResultRow.toMyObject() = MyObject(this[MyObjects.ID], this[MyObjects.userID], this[MyObjects.description], Color(this[MyObjects.color]), this[MyObjects.count])

    override fun getMyObject(ID: Int): MyObject? = DB.transaction {
        MyObjects.select { MyObjects.ID eq ID }.singleOrNull()?.toMyObject()
    }

    override fun updateMyObject(ID: Int, description: String?, color: Color?, count: Long?): Unit = DB.transaction {
        MyObjects.update({ MyObjects.ID eq ID }) {
            if (description != null) it[MyObjects.description] = description
            if (color != null) it[MyObjects.color] = color.value
            if (count != null) it[MyObjects.count] = count
        }
    }

    override fun close() = Unit

DAOFacadeCache.kt

import kotlinx.css.Color
import org.ehcache.CacheManagerBuilder
import org.ehcache.config.CacheConfigurationBuilder
import org.ehcache.config.ResourcePoolsBuilder
import org.ehcache.config.persistence.CacheManagerPersistenceConfiguration
import org.ehcache.config.units.EntryUnit
import org.ehcache.config.units.MemoryUnit
import java.io.File

class DAOFacadeCache(private val delegate: DAOFacade, storage: File) : DAOFacade {
    private val myObjectCacheAlias = "MyObject Cache"
    private val cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
        .with(CacheManagerPersistenceConfiguration(storage))
        .withCache(myObjectCacheAlias, CacheConfigurationBuilder.newCacheConfigurationBuilder<Int, MyObject>()
                .withResourcePools(
                    ResourcePoolsBuilder.newResourcePoolsBuilder()
                        .heap(1024, EntryUnit.ENTRIES)
                        .offheap(16, MemoryUnit.MB)
                        .disk(128, MemoryUnit.MB, true)
                )
                .buildConfig(Int::class.javaObjectType, MyObject::class.java)
        ).build(true)

    private val myObjectCache = cacheManager.getCache(myObjectCacheAlias, Int::class.javaObjectType, MyObject::class.java)

    override fun getMyObject(ID: Int): MyObject? = myObjectCache[ID].takeUnless { it == null } ?: delegate.getMyObject(ID)?.also {
        myObjectCache.put(ID, it)
    }

    override fun updateMyObject(ID: Int, description: String?, color: Color?, count: Long?) {
        getMyObject(ID)?.let {
            if (description != null) it.description = description
            if (color != null) it.color = color
            if (count != null) it.count = count
        }
    }

    override fun close() = try {
        delegate.close()
    } finally {
        cacheManager.close()
    }

在我的应用程序中,我创建一个DAOFacade,如下所示:

import com.mchange.v2.c3p0.ComboPooledDataSource
import org.h2.Driver
import org.jetbrains.exposed.sql.Database
import java.io.File

val dir = File("/build/db")

val pool = ComboPooledDataSource().apply {
    driverClass = Driver::class.java.name
    jdbcUrl = "jdbc:h2:file:${dir.canonicalFile.absolutePath}"
    user = ""
    password = ""
}

val DAO: DAOFacade = DAOFacadeCache(DAOFacadeDatabase(Database.connect(pool)), File(dir.parentFile, "ehcache"))

我的想法是跟踪ID的{​​{1}}字段中被修改的MyObjectSet<Int>中的{{1} }函数将更改保存在DAOFacadeCache数据库中。

但是,此解决方案的问题是closedelegate中的MyObject可能会在缓存关闭之前从缓存中逐出(可能会丢失更改)

是否有可能告诉缓存在将对象从内存中逐出之前对对象执行某些操作?

0 个答案:

没有答案