package aceboot::orm.common
/**
* 事务作用域(对标 TypeORM EntityManager 在 `transaction(em => ...)` 回调里暴露的句柄)。
* 由 EntityManager.transaction 注入回调,内部操作共享同一数据源/连接/事务边界:
* 任一操作抛异常即整体回滚(由外层 DataSource.transaction 兜底)。
* 这里的 save/insert/update/deleteById 仅是跨实体仓储的统一委托——仓储必须绑定到同一数据源
* (@Entity 宏生成的仓储默认用全局数据源,与 EntityManager.global 一致)。
*/
public class TransactionScope {
let ds: DataSource
init(ds: DataSource) {
this.ds = ds
}
/** 暴露事务所在数据源(需要直接走 driver/自定义 SQL 时用)。 */
public func dataSource(): DataSource {
ds
}
/** 在事务内持久化(空主键 insert,否则 update),返回主键。 */
public func save<T>(repo: Repository<T>, e: T): Int64 {
repo.save(e)
}
/** 在事务内插入,返回自增主键。 */
public func insert<T>(repo: Repository<T>, e: T): Int64 {
repo.insert(e)
}
/** 在事务内按主键更新。 */
public func update<T>(repo: Repository<T>, e: T): Unit {
repo.update(e)
}
/** 在事务内按主键删除。 */
public func deleteById<T>(repo: Repository<T>, id: DbValue): Unit {
repo.deleteById(id)
}
}
/**
* 实体管理器(对标 TypeORM EntityManager):跨实体在同一事务里编排写操作。
* `em.transaction { tx => tx.save(repoA, a); tx.save(repoB, b) }` 把回调包进数据源事务,
* 全部操作共用同一连接/事务边界——任一步抛异常则整体回滚。
* 通过 EntityManager.global() 绑定全局数据源(与宏生成的无参仓储一致)。
*/
public class EntityManager {
let ds: DataSource
public init(ds: DataSource) {
this.ds = ds
}
/** 绑定全局数据源的管理器(与 @Entity 宏生成的无参仓储同源)。 */
public static func global(): EntityManager {
EntityManager(globalDataSource())
}
/** 暴露底层数据源。 */
public func dataSource(): DataSource {
ds
}
/**
* 在一个事务里执行 body(注入 TransactionScope):成功 commit,异常 rollback 并重抛。
* 跨实体原子性由共享连接保证(各仓储须绑定同一数据源)。
*/
public func transaction(body: (TransactionScope) -> Unit): Unit {
let scope = TransactionScope(ds)
ds.transaction({=> body(scope)})
}
}
/**
* 查询执行器(对标 TypeORM QueryRunner):手动 begin/commit/rollback,绑定一条连接。
* 当前实现绑定数据源的共享连接(单线程/共享连接驱动适用);连接获取/释放接口为
* 未来连接池(F7)预留——`release()` 现为空操作,池化后从池借/还连接。
* 典型用法:
* let qr = QueryRunner.global()
* qr.startTransaction()
* try { repo.insert(a); repo.insert(b); qr.commitTransaction() }
* catch (e: Exception) { qr.rollbackTransaction(); throw e }
* finally { qr.release() }
*/
public class QueryRunner {
let ds: DataSource
var active: Bool = false
public init(ds: DataSource) {
this.ds = ds
}
/** 绑定全局数据源的执行器。 */
public static func global(): QueryRunner {
QueryRunner(globalDataSource())
}
/** 绑定的连接驱动(后续操作经它执行,保证同一事务边界)。 */
public func connection(): Driver {
ds.driver
}
/** 数据源句柄。 */
public func dataSource(): DataSource {
ds
}
/** 当前是否处于活动事务中。 */
public func isTransactionActive(): Bool {
active
}
/** 开启事务(driver.begin)。重复开启抛 OrmException。 */
public func startTransaction(): Unit {
if (active) {
throw OrmException("QueryRunner: 事务已开启,不能重复 startTransaction")
}
ds.driver.begin()
active = true
}
/** 提交事务(driver.commit)。未开启事务抛 OrmException。 */
public func commitTransaction(): Unit {
if (!active) {
throw OrmException("QueryRunner: 无活动事务,无法 commit")
}
ds.driver.commit()
active = false
}
/** 回滚事务(driver.rollback)。未开启事务抛 OrmException。 */
public func rollbackTransaction(): Unit {
if (!active) {
throw OrmException("QueryRunner: 无活动事务,无法 rollback")
}
ds.driver.rollback()
active = false
}
/**
* 释放连接(归还连接池)。当前为共享连接,空操作;连接池(F7)接入后从此归还。
* 若仍在事务中释放,先回滚以免悬挂事务。
*/
public func release(): Unit {
if (active) {
ds.driver.rollback()
active = false
}
}
}