我需要为我的应用程序设置一个 mysql 会话变量,以便按预期使用 MariaDB Galera 集群。SQL 调用是:SET SESSION wsrep_sync_wait = 1
. 当应用程序使用数据库时,它应始终设置。我使用 EclipseLink 作为 JPA 提供程序。
我的问题是:实现这一目标的最佳方法是什么?
选项 1:EclipseLink 会话定制器
在 中注册会话定制器persistence.xml
:
public class SessionCustomizerImpl implements org.eclipse.persistence.config.SessionCustomizer {
private final static String WSREP_SYNC_WAIT_CHECK_SQL = "SHOW SESSION VARIABLES LIKE 'wsrep_sync_wait'";
private final static String WSREP_SYNC_WAIT_SET_SQL = "SET SESSION wsrep_sync_wait = 1";
@Override
public void customize(Session session) throws Exception {
Vector result = session.executeSQL(WSREP_SYNC_WAIT_CHECK_SQL);
if ((result != null) && !result.isEmpty()) {
session.executeNonSelectingSQL(WSREP_SYNC_WAIT_SET_SQL);
// Galera connection detected; wsrep_sync_wait set to 1
} else {
// No Galera connection detected; wsrep_sync_wait not set
}
}
}
Run Code Online (Sandbox Code Playgroud)
这对我不起作用。从 EntityManager 查询会话变量返回值0
。
选项 2:EntityManager 工厂
每次创建新的 EntityManager 时,都会执行 SQL。
public class SyncWaitEntityManagerFactory implements Factory<EntityManager> {
private final EntityManagerFactory emf;
@Inject
public SyncWaitEntityManagerFactory(EntityManagerFactory emf) {
this.emf = emf;
}
@Override
public EntityManager provide() {
final EntityManager em = emf.createEntityManager();
// set it
em.getTransaction().begin();
em.createNativeQuery("SET SESSION wsrep_sync_wait = 1").executeUpdate();
em.getTransaction().commit();
return em;
}
@Override
public void dispose(EntityManager instance) {
if (instance.isOpen()) {
instance.close();
}
}
}
Run Code Online (Sandbox Code Playgroud)
这有效,但我不确定它是否过大。此外,我担心事务的成本,这仅由 需要Query#executeUpdate()
,而不是实际的 SQL 调用。
选项 3:通过 JDBC URL
将变量和值附加到 JDBC URL(有关详细信息,请参见此处):
String jdbcUrl = "jdbc:mysql://db.example.test:3306/"+ JDBC_DB
+"?sessionVariables=wsrep_sync_wait=1";
Properties p = new Properties();
p.put("javax.persistence.jdbc.url", jdbcUrl);
p.put("javax.persistence.jdbc.user", JDBC_USER);
p.put("javax.persistence.jdbc.password", JDBC_PASSWORD);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU", p);
EntityManager entityManager = emf.createEntityManager();
Run Code Online (Sandbox Code Playgroud)
不错的解决方案。为我工作;无需努力,无需交易。缺点:我无法捕获异常(例如:首先检查变量是否存在,然后设置它——允许在不支持/使用此特定变量的系统上部署代码)。
Rad*_*ZIN -1
您还可以使用切面在每次调用 getConnection() 时执行查询,这基本上适用于每个事务(切面在调用后设置,以便我们拥有有效的连接对象):
@Component
@Aspect
public class CustomConnectionPreparer implements ConnectionPreparer
{
@AfterReturning(pointcut = "execution(* *.getConnection(..))", returning = "connection")
public Connection prepare(Connection connection) throws SQLException {
// execute the query (also exception handling)
try (Statement statement = connection.createStatement()) {
statement.execute("SET SESSION wsrep_sync_wait = 1");
} catch (SQLException e) {
throw e;
}
return connection;
}
}
Run Code Online (Sandbox Code Playgroud)
在将连接返回给调用者之前,您需要执行查询,并且应该始终设置该值。