Skip to main content

数据库-高级应用

事务#

框架原生支持单数据源事务、多数据源事务、分布式事务,分布式事务会在微服务版块专题介绍,这里只对单数据源事务和多数据源事务进行讲解。 有2种方式声明事务:

  1. 通过在服务类或控制器类的方法上添加@Transactional注解即可自动支持事务。@Transactional注解也可以直接加在类上,这样就表示这个类的所有方法都需要事务支持。 @Transactional注解能透明的识别处理单数据源和多数据源事务,无需额外特别的设定。需要注意的是,注解方式的事务声明需要通过依赖注入该类才有效,直接通过new创建对象是不能自动生效的。
  2. 在程序中显示的调用事务处理器。由于后续版本将对该功能做出改变,相关文档随后发布。

单数据源事务#

顾名思义,单数据源事务是指事务范围内的数据库操作都是针对同一个数据源,即同一个数据库连接。下面的例子是针对的同一个数据源main:

@Service
public class TxService extends BusinessService {
private static final Log logger = LogFactory.getLog(TxService.class);
@Autowired
private AutoAdvancedService autoService;
@Transactional
public Boolean singleDatasource(boolean makeTrouble) {
String name = "testForTx";
int age = 66;
int gender = 0;
// 调用AutoAdvancedService中的insertRecord方法向主数据源插入一条记录
if(autoService.insertRecord(name, age, gender)){
logger.info("==> datasource:main, insert record name=testForTx, age=66, gender=0, success !");
// 参数makeTrouble为true时,人为制造异常,让事务失败,查看以上数据库操作回滚情况
if(makeTrouble) {
throw new RuntimeException("Making trouble for transaction to break down");
}
// 调用AutoAdvancedService中的getByName方法,根据name获取刚刚插入的这条记录
Demo demo = autoService.getByName(name);
// 对该记录进行修改并调用该记录的update方法提交更新的数据。
boolean ret = demo.setAge(55).setGender(1).update();
if(ret) {
logger.info("==> datasource:main, update record name=testForTx, age=55, gender=1, success !");
} else {
logger.warn("==> datasource:main, update record name=testForTx, age=55, gender=1, failure !");
}
return ret;
}
return false;
}
public boolean clear(){
return autoService.deleteRecord("testForTx");
}
}

多数据源事务#

多数据源事务是指事务范围内的数据库操作涉及到多个数据源,即多个不同的数据库连接,@Transactional注解能透明的识别处理单数据源和多数据源事务。下面的例子针对的是2个不同的数据源main和test:

@Service
public class TxService extends BusinessService {
private static final Log logger = LogFactory.getLog(TxService.class);
@Autowired
private AutoAdvancedService autoService;
@Transactional
public Boolean crossDatasource(boolean makeTrouble) {
String name = "testForTx";
int age = 66;
int gender = 0;
// 调用AutoAdvancedService中的insertRecord方法向主数据源main插入一条记录
if(autoService.insertRecord(name, age, gender)){
logger.info("==> datasource:main, insert record name=testForTx, age=66, gender=0, success !");
// 调用AutoAdvancedService中的insertRecord1方法向辅数据源test插入一条记录,具体请查看AutoAdvancedService的insertRecord1方法代码
boolean ret = autoService.insertRecord1(name, 77, 1);
if(ret) {
logger.info("==> datasource:test, insert record name=testForTx, age=77, gender=1, success !");
} else {
logger.warn("==> datasource:test, insert record name=testForTx, age=77, gender=1, failure !");
}
// 参数makeTrouble为true时,人为制造异常,让事务失败,查看以上数据库操作回滚情况
if(makeTrouble) throw new RuntimeException("Making trouble for transaction to break down");
return ret;
}
return false;
}
public boolean clear(){
return autoService.deleteRecord("testForTx");
}
}

事件#

框架导出了大量的数据库底层事件,供开发时的调试以及应用扩展需要。

JDBC事件#

框架支持大量jdbc事件,按事件类型和需要划分为多种接口,ConnectionListener接口适用于jdbc连接相关事件,TransactionListener接口适用于jdbc事务相关事件,StatementListener接口适用于jdbc交互相关事件,ExecuteListener接口适用于jdbc命令及SQL执行相关事件,ExecuteBatchListener接口适用于jdbc批操作相关事件,ResultSetListener接口适用于jdbc结果集合相关事件, 还有针对使用较频繁的事件进行了封装的AnyExecuteListener和SimpleJdbcEventListener可供继承使用。下面实例继承自SimpleJdbcEventListener类,只对SQL执行前和执行后的事件进行监听:

public class JdbcEventListener extends SimpleJdbcEventListener {
@Override
public String onBeforeAnyExecute(StatementInformation statementInformation) throws SQLException
{
System.out.println("JdbcEvent: ==> SQL: " + statementInformation.getStatementQuery());
return statementInformation.getStatementQuery();
}
@Override
public void onAfterAnyExecute(StatementInformation statementInformation, long timeElapsedNanos, SQLException e)
{
System.out.println("JdbcEvent: ==> Time elapsed: " + statementInformation.getTotalTimeElapsed());
}
}

然后在应用初始化时加载该事件监听器:

public class Main extends Application {
@Override
protected void initialize() {
dbManager().addJdbcEventListener(new JdbcEventListener());
}
public static void main(String[] args) {
Ready.For(Main.class).Work(args);
}
}

数据变更事件#

有时候需要知道数据表的数据发生了改变,方便对缓存或其他事务进行处理,特别提供了统一的数据变更事件。事件监听器需要实现接口DbChangeListener,见下面实例:

public class DbChangeEventListener implements DbChangeListener {
@Override
public void onInserted(DbChangeEvent event) {
System.out.println("DbChangeEvent: ==> " + event.getTable() + " | " + event.getType() + " | " + Arrays.toString(event.getId()));
}
@Override
public void onUpdated(DbChangeEvent event) {
System.out.println("DbChangeEvent: ==> " + event.getTable() + " | " + event.getType() + " | " + Arrays.toString(event.getId()));
}
@Override
public void onDeleted(DbChangeEvent event) {
System.out.println("DbChangeEvent: ==> " + event.getTable() + " | " + event.getType() + " | " + Arrays.toString(event.getId()));
}
@Override
public void onReplaced(DbChangeEvent event) {
System.out.println("DbChangeEvent: ==> " + event.getTable() + " | " + event.getType() + " | " + Arrays.toString(event.getId()));
}
@Override
public void onMerged(DbChangeEvent event) {
System.out.println("DbChangeEvent: ==> " + event.getTable() + " | " + event.getType() + " | " + Arrays.toString(event.getId()));
}
}

然后在应用初始化时加载该事件监听器:

public class Main extends Application {
@Override
protected void initialize() {
// 这里设置监听器监听demo表的变更事件
dbManager().addDbChangeListener(dbManager().getTable(Demo.class).getName(), new DbChangeEventListener());
}
public static void main(String[] args) {
Ready.For(Main.class).Work(args);
}
}

需要注意的是数据变更事件发出后,如果最终事务执行失败而回滚的情况。利用该事件时需要自行考虑到此种情况的应对。

更多高级应用#

以上只列举部分重点内容,后续逐步完善更多具体的文档,并对重点内容进行专题描述。