【发布时间】:2017-01-09 14:32:56
【问题描述】:
我想通过 Spring JDBC 将 JavaFX 与 DB 访问一起使用。但是我对 Spring 完全陌生,似乎无法完全理解它的功能,尤其是事务处理......
我在我的项目中添加了以下依赖项:
compile 'org.springframework.boot:spring-boot-starter-jdbc'
runtime 'mysql:mysql-connector-java'
...当 GUI 应用程序在 DB 上执行操作时,我想使用 Spring 事务处理机制。据我了解,以下代码应该:
- 初始化并启动 JavaFX 应用程序 - 创建并显示 GUI 线框
- 初始化 Spring
- 配置和注入 JdbcTemplate 依赖项
- 启动事务处理机制并开始事务
- 使用 jdbcTemplate 对象在
for loop的 DB 中创建 5 个条目 - 模拟错误(通过抛出
RuntimeException) - 恢复对 DB 的操作
- 退出
所以,总结一下:当 RuntimeException 被抛出到注释为 @Transactional 的方法中时,它应该在应用程序退出之前恢复由该方法创建的所有条目,不是吗?
但是,所有创建的条目都永久保留在数据库中(应用程序退出后我可以在那里看到它们)。所以首先 - 我是否正确理解这些交易应该如何运作?如果是这样,那么如何让它们按我的预期实际工作?
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
@SpringBootApplication
public class SpringTransactional extends Application {
private Pane viewPane;
private ConfigurableApplicationContext springContext;
/** application.properties:
spring.datasource.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/db_name?useSSL=false&serverTimezone=UTC
spring.datasource.username = db_username
spring.datasource.password = username123
*/
@Autowired
private JdbcTemplate jdbcTemplate;
public static void main(String[] args) {
launch(args);
}
@Override
public void init() throws Exception {
springContext = SpringApplication.run(SpringTransactional.class);
springContext.getAutowireCapableBeanFactory().autowireBean(this);
}
@Override
public void stop() throws Exception {
springContext.close();
}
@Override
public void start(Stage primaryStage) {
viewPane = assembleView(primaryStage);
try {
db_transaction_test();
} catch (RuntimeException e) {
e.printStackTrace();
}
Platform.exit();
}
private Pane assembleView(Stage primaryStage) {
VBox rootPane = new VBox();
rootPane.setSpacing(10);
rootPane.setPadding(new Insets(10));
rootPane.setStyle("-fx-base: #84a7ad;");
rootPane.getChildren().add(new Label("GUI goes here."));
primaryStage.setScene(new Scene(rootPane));
primaryStage.setResizable(false);
primaryStage.show();
return rootPane;
}
@Transactional
private void db_transaction_test() {
for (int i = 0; i < 10; i++) {
try {
int entry_name = getEntryId("entry_" + i);
System.out.println("Created entry id=" + entry_name);
} catch (DaoException e) {
e.printStackTrace();
}
if (i == 5) {
throw new RuntimeException("Testing data upload procedure break.");
}
}
}
/** DB creation and schema:
CREATE DATABASE db_name;
CREATE USER db_username;
USE db_name;
GRANT ALL ON db_name.* TO db_username;
SET PASSWORD FOR spz = PASSWORD('username123');
FLUSH PRIVILEGES;
CREATE TABLE Entry (
entry_ID INT NOT NULL AUTO_INCREMENT,
name TEXT NOT NULL,
PRIMARY KEY (entry_ID)
);
*/
private int getEntryId(String entryName) throws DaoException {
List<DbEntry> dbEntries = retrieveEntriesFor(entryName);
if (dbEntries.size() == 1) {
return dbEntries.get(0).getEntry_ID();
} else if (dbEntries.size() == 0) {
String sqlInsert = "INSERT INTO Entry (name) VALUES (?)";
jdbcTemplate.update(sqlInsert, entryName);
dbEntries = retrieveEntriesFor(entryName);
if (dbEntries.size() == 1) {
return dbEntries.get(0).getEntry_ID();
} else {
throw new DaoException("Invalid results amount received after creating new (" + dbEntries.size() + ") when getting entry for name: " + entryName);
}
} else {
throw new DaoException("Invalid results amount received (" + dbEntries.size() + ") when getting entry for name: " + entryName);
}
}
private List<DbEntry> retrieveEntriesFor(String entryName) {
return jdbcTemplate.query("SELECT * FROM Entry WHERE name=?;", (ResultSet result, int rowNum) -> unMarshal(result), entryName);
}
private DbEntry unMarshal(ResultSet result) throws SQLException {
DbEntry dbEntry = new DbEntry();
dbEntry.setEntry_ID(result.getInt("entry_ID"));
dbEntry.setName(result.getString("name"));
return dbEntry;
}
public class DbEntry {
private int entry_ID;
private String name;
int getEntry_ID() { return entry_ID; }
void setEntry_ID(int entry_ID) { this.entry_ID = entry_ID; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
private class DaoException extends Throwable {
DaoException(String err_msg) { super(err_msg); }
}
}
【问题讨论】:
标签: spring javafx spring-boot autowired transactional