在Data Geekery ,我们喜欢Java。 而且,由于我们真的很喜欢jOOQ的流畅的API和查询DSL ,我们对Java 8将为我们的生态系统带来什么感到非常兴奋。 我们已经写了一些关于Java 8好东西的博客 ,现在我们觉得是时候开始一个新的博客系列了……
Java 8星期五
每个星期五,我们都会向您展示一些不错的教程风格的Java 8新功能,这些功能利用了lambda表达式,扩展方法和其他好东西。 您可以在GitHub上找到源代码 。
Java 8 Goodie:本地事务范围
JavaScript人士经常滥用匿名函数来创建本地范围。 像任何其他语言功能一样,这可能会被滥用 ,但是在某些情况下,本地作用域确实很棒。 Java还允许本地作用域,尽管在Java 8之前,这同样麻烦:
JavaScript
(function() {
var local = function() {
scoping();
},
scoping = function() {
alert('If you really must');
};
local();
})();
Java
new Object() {
void local() {
scoping();
}
void scoping() {
System.out.println(
"Ouch, my fingers. Too much typing");
}
}.local();
尽管JavaScript人士将此称为设计模式,但两个示例看起来都非常尴尬。 即使这两段代码大致相等,也没人会在Java中创建这样的本地范围。
尴尬可以是JavaScript中的一种设计模式。
Java 8中的本地作用域
但是,对于Java 8,一切都会改变,本地作用域也会改变。 让我们看一下如何为事务创建本地语义范围。 为此,我们将创建两种类型。 事务接口:
@FunctionalInterface
interface Transactional {
void run(DSLContext ctx);
}
对于该示例,我们将使用jOOQ来避免检查异常和冗长的语句创建。 您可以用您选择的SQL API替换它。 因此,jOOQ为我们提供了一个本地范围内的ctx
对象,该对象隐式包含了事务状态。 使用TransactionRunner生成此事务状态:
class TransactionRunner {
private final boolean silent;
private final Connection connection;
TransactionRunner(Connection connection) {
this(connection, true);
}
TransactionRunner(Connection connection,
boolean silent) {
this.connection = connection;
this.silent = silent;
}
void run(Transactional tx) {
// Initialise some jOOQ objects
final DefaultConnectionProvider c =
new DefaultConnectionProvider(connection);
final Configuration configuration =
new DefaultConfiguration()
.set(c).set(SQLDialect.H2);
try {
// Run the transaction and pass a jOOQ
// DSLContext object to it
tx.run(DSL.using(configuration));
// If we get here, then commit the
// transaction
c.commit();
}
catch (RuntimeException e) {
// Any exception will cause a rollback
c.rollback();
System.err.println(e.getMessage());
// Eat exceptions in silent mode.
if (!silent)
throw e;
}
}
}
上面是框架代码,我们只编写一次。 从现在开始,我们可以在Java程序中轻松使用上述API。 为此,我们将像这样设置一个TransactionRunner:
public static void main(String[] args)
throws Exception {
Class.forName("org.h2.Driver");
try (Connection c = DriverManager.getConnection(
"jdbc:h2:~/test-scope-goodies",
"sa", "")) {
c.setAutoCommit(false);
TransactionRunner silent =
new TransactionRunner(c);
// Transactional code here ...
}
}
现在,请看Java 8的奇观!
// This is a transaction
silent.run(ctx -> {
ctx.execute("drop table if exists person");
ctx.execute("create table person(" +
" id integer," +
" first_name varchar(50)," +
" last_name varchar(50)," +
" primary key(id)"+
")");
});
// And this is also one transaction
silent.run(ctx -> {
ctx.execute("insert into person" +
" values(1, 'John', 'Smith');");
ctx.execute("insert into person" +
" values(1, 'Steve', 'Adams');");
// Ouch, fails -------^
// Transaction rolls back
});
// And this is also one transaction
silent.run(ctx -> {
ctx.execute("insert into person" +
" values(2, 'Jane', 'Miller');");
// Works, yay!
});
// And this is also one transaction
silent.run(ctx -> {
ctx.execute("insert into person" +
" values(2, 'Anne', 'Roberts');");
// Ouch, fails -------^
// Transaction rolls back
});
从上面我们能得到什么? 让我们检查:
silent.run(ctx -> {
System.out.println(
ctx.fetch("select * from person"));
});
上面的程序将产生以下输出:
SQL [insert into person values(1, 'Steve', 'Adams');];
Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.PERSON(ID)"; SQL statement:
insert into person values(1, 'Steve', 'Adams'); [23505-174]
SQL [insert into person values(2, 'Anne', 'Roberts');];
Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.PERSON(ID)"; SQL statement:
insert into person values(2, 'Anne', 'Roberts'); [23505-174]
+----+----------+---------+
| ID|FIRST_NAME|LAST_NAME|
+----+----------+---------+
| 2|Jane |Miller |
+----+----------+---------+
因此,我们的提交和回滚按预期工作!
嵌套交易
我们还可以创建对TransactionRunner的嵌套调用,例如,当我们在调用其他方法的方法内部时。 为此,必须调整我们的TransactionRunner以计算嵌套级别,并删除“静音”功能。 另一方面,以这种方式实现保存点功能将非常容易。 每次嵌套另一个事务时,我们都会创建一个新的保存点。
结论
与本系列一样,我们没有发明任何新东西。 所有这些事情都可以通过香草Java 7完成。但是,此TransactionRunner的客户端代码肯定不会像我们的lambda那样精简。
在本系列博客的下周,我们将研究Java 8如何使您非常轻松地定义本地缓存范围,请继续关注!
翻译自: https://www.javacodegeeks.com/2014/02/java-8-friday-goodies-local-transaction-scope.html