日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Sybase使用Spring的只讀事物報 Use ‘set readonly off‘ to execute BEGIN TRANSACTION.

作者:iuie_sl 更新時間: 2022-07-13 編程語言

背景:
公司的dev的sybase升級的,以前能夠好好運行的spring data里面SimpleJpaRepository的方法,現(xiàn)在都報錯

Caused by: java.sql.SQLException: Failed to execute COMMIT TRANSACTION, because this is a read-only connection. Read-only connections can only execute SELECT statements. Use 'set readonly off' to execute COMMIT TRANSACTION.

	at com.sybase.jdbc4.jdbc.SybConnection.getAllExceptions(SybConnection.java:2780)
	at com.sybase.jdbc4.jdbc.SybConnection.handleSQLE(SybConnection.java:2648)
	at com.sybase.jdbc4.jdbc.SybConnection.commit(SybConnection.java:1635)
	at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.commit(AbstractLogicalConnectionImplementor.java:81)
	... 106 more

發(fā)現(xiàn)錯誤的原因

  一路跟蹤代碼里面發(fā)現(xiàn)SimpleJpaRepository的定義是這樣的
@Repository
@Transactional(
    readOnly = true
)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID>

然后@Transactional里面事物的默認propagation是Propagation.REQUIRED;,所以這個類里面的所有方法如果調用方沒有事物,就會創(chuàng)建一個新的事物,包括findAll(), findById這些查詢方法,并且設置連接的readOnly為true。這種事物叫做只讀事物(一次執(zhí)行多次查詢來統(tǒng)計某些信息,這時為了保證數據整體的一致性,要用只讀事務)

然后看看代碼里面sybase設置連接只讀屬性的地方在類SybConnection

public void setReadOnly(boolean var1) throws SQLException {
        if (LogUtil.isLoggingEnabled(LOG)) {
            if (LOG.isLoggable(Level.FINER)) {
                LOG.finer(this._logId + " setReadOnly(boolean = [" + var1 + "])");
            } else if (LOG.isLoggable(Level.FINE)) {
                LOG.fine(this._logId + " setReadOnly(boolean)");
            }
        }

        this.checkConnection();

        try {
            this._protocol.setOption((ProtocolContext)null, 3, var1);
        } catch (SQLException var3) {
            this.handleSQLE(var3);
        }

        this._readOnly = var1;
    }

然后繼續(xù)往下追蹤發(fā)現(xiàn)設置readyOnly執(zhí)行在sql在這個里面

select query from master..spt_mda where mdinfo='SET_READONLY_FALSE' or mdinfo='SET_READONLY_TRUE'

sybase沒升級之前這個查詢出來是空的,現(xiàn)在查詢出來為set readonly on,
所以當調用SimpleJpaRepository的findAll方法的時候相當是執(zhí)行下面的sql

set readonly ON
BEGIN TRAN 
SELECT * FROM xxxx
COMMIT TRAN

這樣就會報下面的錯
Error (456) Failed to execute BEGIN TRANSACTION, because this is a read-only connection. Read-only connections can only execute SELECT statements. Use ‘set readonly off’ to execute BEGIN TRANSACTION.

可見sybase升級后不支持spring的只讀事物

解決方案

  1. 最簡單的解決方案是在你寫的jpa類上面在加一個@Transactional,并在設置propagation為SUPPORTS, spring在找事物注解的時候,是先找單前接口,找不到才找父類的,這樣你寫的@Transactional注解就會覆蓋掉SimpleJpaRepository上面的注解,并且,如果查詢沒帶事物這里就不會創(chuàng)建一個事物。
@Repository
@Transactional(propagation = Propagation.SUPPORTS)
public interface xxxx extends JpaRepository<xx, String>
  1. 第二種解決方法麻煩點,但是改動更加少,你寫一個和SimpleJpaRepository一摸一樣的類,什么類名包名完全一樣,只是修改下頭上的@Transactional注解,改成
@Repository
@Transactional(
    readOnly = true,
    propagation = Propagation.SUPPORTS
)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID>

然后導出這個jar包,注意這個jar包的包路徑一定要在org.springframework.data:spring-data-jpa:2.0.0的前面

包路徑越靠前,越先被加載。換句話說,如果靠前的jar包里的類被加載了,后面jar包里有同名同路徑的類,就會被忽略掉,不會被加載。 這樣你就用自己的SimpleJpaRepository替換掉了spring data自帶的SimpleJpaRepository

原文鏈接:https://blog.csdn.net/iuie_sl/article/details/125750877

欄目分類
最近更新