Code Monkey home page Code Monkey logo

Comments (9)

emacarron avatar emacarron commented on June 18, 2024

Hi,

How are you going to control the tx manually. Which api are you going to
use?

2014-07-18 17:42 GMT+02:00 Zen Zhong [email protected]:

I'm running mybatis-spring 1.2.2, I need to control transaction manually
for part of DAO (for integration with datagrid via JTA), transaction is
controlled by SqlSession, SqlSession is got from sqlSessionFactory manually
in code, and sqlSessionFactory is a spring bean:

When logs show "DEBUG [main]
org.mybatis.spring.transaction.SpringManagedTransaction: JDBC Connection
com.mysql.jdbc.JDBC4Connection @ 7f946a32 will not be managed by Spring",
my rollback doesn't work.

From org.mybatis.spring.transaction.SpringManagedTransactionFactory's
javadoc: "If Spring's transaction handling is active it will no-op all
commit/rollback/close calls assuming that the Spring transaction manager
will do the job. If it is not it will behave like JdbcTransaction.", to my
understanding, it should be rolled back.

Part code of SpringManagedTransactionFactory:

public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
return new SpringManagedTransaction(dataSource);
}

autoCommit is ignored, always. Is it a bug?

I'll push my whole testing project to GitHub if necessary.

Currently, a workaround is to set JdbcTransactionFactory as
transactionFactory, configuration:


Reply to this email directly or view it on GitHub
#39.

from spring.

 avatar commented on June 18, 2024

Hi,

via SqlSession, sqlSessionFactory.openSession(false) -> sqlSession.rollback()

I've pushed the testing project to https://github.com/zenzhong8383/mybatis_test , the testing failed method is TestSqlSessionFactoryBean.testMybatisSpring1

from spring.

emacarron avatar emacarron commented on June 18, 2024

Is autocommit off?

2014-07-19 17:06 GMT+02:00 Zen Zhong [email protected]:

Hi,

via SqlSession, sqlSessionFactory.openSession(false) ->
sqlSession.rollback()

I've pushed the testing project to
https://github.com/zenzhong8383/mybatis_test , the testing failed method
is TestSqlSessionFactoryBean.testMybatisSpring1


Reply to this email directly or view it on GitHub
#39 (comment).

from spring.

 avatar commented on June 18, 2024

autocommit is off.
sqlSession is assigned as "SqlSessionFactory.openSession(boolean autoCommit)", autoCommit is false.

In fact, there're 3 test cases: testMybatisSpring1/testMybatisSpring2/testMybatis, all of them will call "testRollback(SqlSessionFactory sqlSessionFactory, List<ImmutablePair<Long, String>> pairs)" method, the difference is they get sqlSessionFactory by different way.

Simplified code:

public class TestSqlSessionFactoryBean {
    private SqlSessionFactory sqlSessionFactory1;
    private SqlSessionFactory sqlSessionFactory2;

    @Before
    public void init() throws SQLException {
        try (AbstractApplicationContext appCtx = new ClassPathXmlApplicationContext("config/applicationContext.xml")) {
            sqlSessionFactory1 = (SqlSessionFactory) appCtx.getBean("sqlSessionFactory1");
            sqlSessionFactory2 = (SqlSessionFactory) appCtx.getBean("sqlSessionFactory2");
        }
        try (SqlSession sqlSession = sqlSessionFactory1.openSession(); Connection conn = sqlSession.getConnection();) {
            try (Statement stmt = conn.createStatement()) {
                stmt.execute("DROP TABLE IF EXISTS mybatis_test");
            }
            try (Statement stmt = conn.createStatement()) {
                stmt.execute("CREATE TABLE mybatis_test (id UNIQUE, name NOT NULL)");
            }
        }
    }

    private void testRollback(SqlSessionFactory sqlSessionFactory) {
        try (SqlSession sqlSession = sqlSessionFactory.openSession(false)) {
            MybatisTestMapper mapper = sqlSession.getMapper(MybatisTestMapper.class);
            mapper.insert(1, "test1");
            sqlSession.rollback();
        }
    }

    // rollback doesn't work
    @Test
    public void testMybatisSpring1() {
        testRollback(sqlSessionFactory1);
    }

    // rollback works
    @Test
    public void testMybatisSpring2() {
        testRollback(sqlSessionFactory2);
    }

    // rollback works
    @Test
    public void testMybatis() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        try (InputStream inputStream = Resources.getResourceAsStream("config/mybatis-config-standalone.xml")) {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
        testRollback(sqlSessionFactory);
    }
}

config/applicationContext.xml
    <bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="config/mybatis-config-spring.xml" />
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="transactionFactory" class="org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory" />
    <bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="config/mybatis-config-spring.xml" />
        <property name="dataSource" ref="dataSource" />
        <property name="transactionFactory" ref="transactionFactory" />
    </bean>

from spring.

emacarron avatar emacarron commented on June 18, 2024

Hi Zen,

MyBatis-Spring is built around an object called SqlSessionTemplate
(following String templates saga like JdbcTemplate). This bean makes your
code participate in an Spring transaction.

You are not using that but injecting a "normal" SqlSessionFactory on your
bean. This SqlSessionFactory is not 100% normal because it will have the
SpringTransactionFactory set instead of the JdbcTransactionFactory. Anyway
they behave almost alike when Spring TX is not active.

Note that there is no magic here, if you call session.rollback() it will
end up call ing connnection.rollback() and changes should rollback. If it
does not, I can only think of autocommit being the culprit.

I would suggest printing conn.getAutocommit() to make sure it is off.
Debugging line by line may bring some light also.

2014-07-20 4:03 GMT+02:00 Zen Zhong [email protected]:

autocommit is off.
sqlSession is assigned as "SqlSessionFactory.openSession(boolean
autoCommit)", autoCommit is false.

In fact, there're 3 test cases:
testMybatisSpring1/testMybatisSpring2/testMybatis, all of them will call
"testRollback(SqlSessionFactory sqlSessionFactory, List> pairs)" method,
the difference is they get sqlSessionFactory by different way.

Simplified code:

public class TestSqlSessionFactoryBean {
private SqlSessionFactory sqlSessionFactory1;
private SqlSessionFactory sqlSessionFactory2;

@Before
public void init() throws SQLException {
    try (AbstractApplicationContext appCtx = new ClassPathXmlApplicationContext("config/applicationContext.xml")) {
        sqlSessionFactory1 = (SqlSessionFactory) appCtx.getBean("sqlSessionFactory1");
        sqlSessionFactory2 = (SqlSessionFactory) appCtx.getBean("sqlSessionFactory2");
    }
    try (SqlSession sqlSession = sqlSessionFactory1.openSession(); Connection conn = sqlSession.getConnection();) {
        try (Statement stmt = conn.createStatement()) {
            stmt.execute("DROP TABLE IF EXISTS mybatis_test");
        }
        try (Statement stmt = conn.createStatement()) {
            stmt.execute("CREATE TABLE mybatis_test (id UNIQUE, name NOT NULL)");
        }
    }
}

private void testRollback(SqlSessionFactory sqlSessionFactory) {
    try (SqlSession sqlSession = sqlSessionFactory.openSession(false)) {
        MybatisTestMapper mapper = sqlSession.getMapper(MybatisTestMapper.class);
        mapper.insert(1, "test1");
        sqlSession.rollback();
    }
}

// rollback doesn't work
@Test
public void testMybatisSpring1() {
    testRollback(sqlSessionFactory1);
}

// rollback works
@Test
public void testMybatisSpring2() {
    testRollback(sqlSessionFactory2);
}

// rollback works
@Test
public void testMybatis() throws IOException {
    SqlSessionFactory sqlSessionFactory;
    try (InputStream inputStream = Resources.getResourceAsStream("config/mybatis-config-standalone.xml")) {
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    testRollback(sqlSessionFactory);
}

}

config/applicationContext.xml



<bean id="transactionFactory" class="org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory" />
<bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="configLocation" value="config/mybatis-config-spring.xml" />
    <property name="dataSource" ref="dataSource" />
    <property name="transactionFactory" ref="transactionFactory" />
</bean>


Reply to this email directly or view it on GitHub
#39 (comment).

from spring.

 avatar commented on June 18, 2024

Hi Eduardo,

I debugged it, some objects' states:
sqlSession.autoCommit=false
sqlSession.executor.transaction is instanceof SpringManagedTransaction
sqlSession.executor.transaction.autoCommit=true
sqlSession.executor.transaction.connection.autoCommit=true

Since sqlSession.executor.transaction.autoCommit=true, SpringManagedTransaction.rollback() doesn't execute "this.connection.rollback();", the related code is:

  public void rollback() throws SQLException {
    if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
      if (logger.isDebugEnabled()) {
        logger.debug("Rolling back JDBC Connection [" + this.connection + "]");
      }
      this.connection.rollback();
    }
  }

SpringManagedTransactionFactory ignore autoCommit; SpringManagedTransaction.openConnection() will set this.autoCommit as "this.connection.getAutoCommit()", it always be true.

And also, SqlSessionTemplate doesn't support rollback. What's the correct way to control transaction manually when current code is based on MyBatis-Spring?

from spring.

emacarron avatar emacarron commented on June 18, 2024

Hi Zen. That makes sense.

Options are:
1.- Configure your datasource to turn autocommit off
2.- Configure the SqlSessionFactoryBean to use JdbcTransactionFactory
3.- Use Spring's programmatic TX management API (
http://mybatis.github.io/spring/transactions.html#programmatic)

Hope this helps!

2014-07-20 16:07 GMT+02:00 Zen Zhong [email protected]:

Hi Eduardo,

I debugged it, some objects' states:
sqlSession.autoCommit=false
sqlSession.executor.transaction is instanceof SpringManagedTransaction
sqlSession.executor.transaction.autoCommit=true
sqlSession.executor.transaction.connection.autoCommit=true

Since sqlSession.executor.transaction.autoCommit=true,
SpringManagedTransaction.rollback() doesn't execute
"this.connection.rollback();", the related code is:

public void rollback() throws SQLException {
if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
if (logger.isDebugEnabled()) {
logger.debug("Rolling back JDBC Connection [" + this.connection + "]");
}
this.connection.rollback();
}
}

SpringManagedTransactionFactory ignore autoCommit;
SpringManagedTransaction.openConnection() will set this.autoCommit as
"this.connection.getAutoCommit()", it always be true.

And also, SqlSessionTemplate doesn't support rollback. What's the correct
way to control transaction manually when current code is based on
MyBatis-Spring?


Reply to this email directly or view it on GitHub
#39 (comment).

from spring.

 avatar commented on June 18, 2024

Thanks, Eduardo. It's impressive to receive replies so quickly, I could
move on now.

2014-07-21 4:17 GMT+08:00 Eduardo Macarron [email protected]:

Hi Zen. That makes sense.

Options are:
1.- Configure your datasource to turn autocommit off
2.- Configure the SqlSessionFactoryBean to use JdbcTransactionFactory
3.- Use Spring's programmatic TX management API (
http://mybatis.github.io/spring/transactions.html#programmatic)

Hope this helps!

2014-07-20 16:07 GMT+02:00 Zen Zhong [email protected]:

Hi Eduardo,

I debugged it, some objects' states:
sqlSession.autoCommit=false
sqlSession.executor.transaction is instanceof SpringManagedTransaction
sqlSession.executor.transaction.autoCommit=true
sqlSession.executor.transaction.connection.autoCommit=true

Since sqlSession.executor.transaction.autoCommit=true,
SpringManagedTransaction.rollback() doesn't execute
"this.connection.rollback();", the related code is:

public void rollback() throws SQLException {
if (this.connection != null && !this.isConnectionTransactional &&
!this.autoCommit) {
if (logger.isDebugEnabled()) {
logger.debug("Rolling back JDBC Connection [" + this.connection + "]");
}
this.connection.rollback();
}
}

SpringManagedTransactionFactory ignore autoCommit;
SpringManagedTransaction.openConnection() will set this.autoCommit as
"this.connection.getAutoCommit()", it always be true.

And also, SqlSessionTemplate doesn't support rollback. What's the
correct
way to control transaction manually when current code is based on
MyBatis-Spring?


Reply to this email directly or view it on GitHub
#39 (comment).


Reply to this email directly or view it on GitHub
#39 (comment).

from spring.

jayramrout avatar jayramrout commented on June 18, 2024

Hi Eduardo,
I am using SqlSessionFactoryBean with below properties along with Mapper interfaces and mybatis:scan in the spring config . So, how do i manually control the transaction now .

<mybatis:scan base-package="jrout.mypackage" />

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="transactionFactory">
            <bean class="org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory" />
        </property>
        <property name="configLocation" value="classpath:mySqlMapConfig.xml" />
        <property name="dataSource" ref="dataSource" />
    </bean>

Is there any working copy of the code which i can refer it to.

from spring.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.