簡體   English   中英

JPA:如何設置 MySQL 會話變量?

[英]JPA: How to set MySQL session variables?

我需要為我的應用程序設置一個 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
        }

    }
}

這對我不起作用。 從 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();
        }
    }

}

這有效,但我不確定它是否過大。 另外,我擔心事務的成本,這只是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();

不錯的解決方案。 為我工作; 無需努力,無需交易。 缺點:我無法捕獲異常(例如:首先檢查變量是否存在,然后設置它——允許在不支持/使用此特定變量的系統上部署代碼)。

您還可以使用切面在每次調用 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;
    }
}

在將連接返回給調用者之前,您執行查詢,並且應該始終設置該值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM