Skip to content

Commit 4a84e3c

Browse files
authored
Merge pull request #327 from jeffgbutler/spring-transactions
Spring Transaction and Cache Tests
2 parents a9f8b46 + a4f054e commit 4a84e3c

File tree

8 files changed

+464
-121
lines changed

8 files changed

+464
-121
lines changed

src/test/java/issues/gh324/Issue324Test.java

Lines changed: 39 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -15,146 +15,65 @@
1515
*/
1616
package issues.gh324;
1717

18-
import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
19-
import org.apache.ibatis.jdbc.ScriptRunner;
20-
import org.apache.ibatis.mapping.Environment;
21-
import org.apache.ibatis.session.Configuration;
22-
import org.apache.ibatis.session.SqlSession;
23-
import org.apache.ibatis.session.SqlSessionFactory;
24-
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
25-
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
26-
import org.junit.jupiter.api.BeforeEach;
2718
import org.junit.jupiter.api.Test;
2819

29-
import java.io.InputStream;
30-
import java.io.InputStreamReader;
31-
import java.sql.Connection;
32-
import java.sql.DriverManager;
33-
import java.util.Optional;
34-
3520
import static org.assertj.core.api.Assertions.assertThat;
3621

37-
public class Issue324Test {
38-
private static final String JDBC_URL = "jdbc:hsqldb:mem:aname";
39-
private static final String JDBC_DRIVER = "org.hsqldb.jdbcDriver";
40-
41-
private SqlSessionFactory sqlSessionFactory;
42-
43-
@BeforeEach
44-
void setup() throws Exception {
45-
Class.forName(JDBC_DRIVER);
46-
InputStream is = getClass().getResourceAsStream("/issues/gh324/CreateDB.sql");
47-
try (Connection connection = DriverManager.getConnection(JDBC_URL, "sa", "")) {
48-
ScriptRunner sr = new ScriptRunner(connection);
49-
sr.setLogWriter(null);
50-
sr.runScript(new InputStreamReader(is));
51-
}
52-
53-
UnpooledDataSource ds = new UnpooledDataSource(JDBC_DRIVER, JDBC_URL, "sa", "");
54-
Environment environment = new Environment("test", new JdbcTransactionFactory(), ds);
55-
Configuration config = new Configuration(environment);
56-
config.addMapper(NameTableMapper.class);
57-
sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
58-
}
22+
class Issue324Test {
23+
private NameService nameService = new NameService();
5924

6025
@Test
6126
void testCacheWithAutoCommitOnUpdate() {
62-
insertRecord();
63-
Optional<NameRecord> returnedRecord = getRecord();
64-
assertThat(returnedRecord).hasValueSatisfying(rr -> {
65-
assertThat(rr.getId()).isEqualTo(1);
66-
assertThat(rr.getName()).isEqualTo("Fred");
67-
});
68-
69-
updateRecordWithAutoCommit();
70-
returnedRecord = getRecord();
71-
assertThat(returnedRecord).hasValueSatisfying(rr -> {
72-
assertThat(rr.getId()).isEqualTo(1);
73-
assertThat(rr.getName()).isEqualTo("Barney");
74-
});
27+
nameService.resetDatabase();
28+
29+
nameService.insertRecord();
30+
assertThat(nameService.getRecord()).hasValueSatisfying(TestUtils::recordIsFred);
31+
assertThat(ObservableCache.getInstance().getHits()).isZero();
32+
33+
assertThat(nameService.getRecord()).hasValueSatisfying(TestUtils::recordIsFred);
34+
assertThat(ObservableCache.getInstance().getHits()).isEqualTo(1);
35+
36+
nameService.updateRecordWithAutoCommit();
37+
assertThat(nameService.getRecord()).hasValueSatisfying(TestUtils::recordIsBarney);
38+
assertThat(ObservableCache.getInstance().getHits()).isZero();
39+
40+
assertThat(nameService.getRecord()).hasValueSatisfying(TestUtils::recordIsBarney);
41+
assertThat(ObservableCache.getInstance().getHits()).isEqualTo(1);
7542
}
7643

7744
@Test
7845
void testCacheWithNoAutoCommitOnUpdateAndNoExplicitCommit() {
79-
insertRecord();
80-
Optional<NameRecord> returnedRecord = getRecord();
81-
assertThat(returnedRecord).hasValueSatisfying(rr -> {
82-
assertThat(rr.getId()).isEqualTo(1);
83-
assertThat(rr.getName()).isEqualTo("Fred");
84-
});
46+
nameService.resetDatabase();
47+
48+
nameService.insertRecord();
49+
assertThat(nameService.getRecord()).hasValueSatisfying(TestUtils::recordIsFred);
50+
assertThat(ObservableCache.getInstance().getHits()).isZero();
51+
52+
assertThat(nameService.getRecord()).hasValueSatisfying(TestUtils::recordIsFred);
53+
assertThat(ObservableCache.getInstance().getHits()).isEqualTo(1);
8554

8655
// the update should rollback
87-
updateRecordWithoutAutoCommitAndNoExplicitCommit();
88-
returnedRecord = getRecord();
89-
assertThat(returnedRecord).hasValueSatisfying(rr -> {
90-
assertThat(rr.getId()).isEqualTo(1);
91-
assertThat(rr.getName()).isEqualTo("Fred");
92-
});
56+
nameService.updateRecordWithoutAutoCommitAndNoExplicitCommit();
57+
assertThat(nameService.getRecord()).hasValueSatisfying(TestUtils::recordIsFred);
58+
assertThat(ObservableCache.getInstance().getHits()).isEqualTo(2);
9359
}
9460

9561
@Test
9662
void testCacheWithNoAutoCommitOnUpdateAndExplicitCommit() {
97-
insertRecord();
98-
Optional<NameRecord> returnedRecord = getRecord();
99-
assertThat(returnedRecord).hasValueSatisfying(rr -> {
100-
assertThat(rr.getId()).isEqualTo(1);
101-
assertThat(rr.getName()).isEqualTo("Fred");
102-
});
103-
104-
updateRecordWithoutAutoCommitAndExplicitCommit();
105-
returnedRecord = getRecord();
106-
assertThat(returnedRecord).hasValueSatisfying(rr -> {
107-
assertThat(rr.getId()).isEqualTo(1);
108-
assertThat(rr.getName()).isEqualTo("Barney");
109-
});
110-
}
63+
nameService.resetDatabase();
11164

112-
private void insertRecord() {
113-
try (SqlSession session = sqlSessionFactory.openSession(true)) {
114-
NameTableMapper mapper = session.getMapper(NameTableMapper.class);
115-
NameRecord record = new NameRecord();
116-
record.setId(1);
117-
record.setName("Fred");
118-
mapper.insert(record);
119-
}
120-
}
65+
nameService.insertRecord();
66+
assertThat(nameService.getRecord()).hasValueSatisfying(TestUtils::recordIsFred);
67+
assertThat(ObservableCache.getInstance().getHits()).isZero();
12168

122-
private void updateRecordWithAutoCommit() {
123-
try (SqlSession session = sqlSessionFactory.openSession(true)) {
124-
NameTableMapper mapper = session.getMapper(NameTableMapper.class);
125-
NameRecord record = new NameRecord();
126-
record.setId(1);
127-
record.setName("Barney");
128-
mapper.updateByPrimaryKey(record);
129-
}
130-
}
69+
assertThat(nameService.getRecord()).hasValueSatisfying(TestUtils::recordIsFred);
70+
assertThat(ObservableCache.getInstance().getHits()).isEqualTo(1);
13171

132-
private void updateRecordWithoutAutoCommitAndNoExplicitCommit() {
133-
// this should rollback
134-
try (SqlSession session = sqlSessionFactory.openSession()) {
135-
NameTableMapper mapper = session.getMapper(NameTableMapper.class);
136-
NameRecord record = new NameRecord();
137-
record.setId(1);
138-
record.setName("Barney");
139-
mapper.updateByPrimaryKey(record);
140-
}
141-
}
142-
143-
private void updateRecordWithoutAutoCommitAndExplicitCommit() {
144-
try (SqlSession session = sqlSessionFactory.openSession()) {
145-
NameTableMapper mapper = session.getMapper(NameTableMapper.class);
146-
NameRecord record = new NameRecord();
147-
record.setId(1);
148-
record.setName("Barney");
149-
mapper.updateByPrimaryKey(record);
150-
session.commit();
151-
}
152-
}
72+
nameService.updateRecordWithoutAutoCommitAndExplicitCommit();
73+
assertThat(nameService.getRecord()).hasValueSatisfying(TestUtils::recordIsBarney);
74+
assertThat(ObservableCache.getInstance().getHits()).isZero();
15375

154-
private Optional<NameRecord> getRecord() {
155-
try (SqlSession session = sqlSessionFactory.openSession()) {
156-
NameTableMapper mapper = session.getMapper(NameTableMapper.class);
157-
return mapper.selectByPrimaryKey(1);
158-
}
76+
assertThat(nameService.getRecord()).hasValueSatisfying(TestUtils::recordIsBarney);
77+
assertThat(ObservableCache.getInstance().getHits()).isEqualTo(1);
15978
}
16079
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright 2016-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package issues.gh324;
17+
18+
import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
19+
import org.apache.ibatis.jdbc.ScriptRunner;
20+
import org.apache.ibatis.mapping.Environment;
21+
import org.apache.ibatis.session.Configuration;
22+
import org.apache.ibatis.session.SqlSession;
23+
import org.apache.ibatis.session.SqlSessionFactory;
24+
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
25+
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
26+
27+
import java.io.InputStream;
28+
import java.io.InputStreamReader;
29+
import java.sql.Connection;
30+
import java.sql.DriverManager;
31+
import java.util.Optional;
32+
33+
public class NameService {
34+
private static final String JDBC_URL = "jdbc:hsqldb:mem:aname";
35+
private static final String JDBC_DRIVER = "org.hsqldb.jdbcDriver";
36+
37+
private final SqlSessionFactory sqlSessionFactory;
38+
39+
public NameService() {
40+
try {
41+
Class.forName(JDBC_DRIVER);
42+
InputStream is = getClass().getResourceAsStream("/issues/gh324/CreateDB.sql");
43+
try (Connection connection = DriverManager.getConnection(JDBC_URL, "sa", "")) {
44+
ScriptRunner sr = new ScriptRunner(connection);
45+
sr.setLogWriter(null);
46+
sr.runScript(new InputStreamReader(is));
47+
}
48+
49+
UnpooledDataSource ds = new UnpooledDataSource(JDBC_DRIVER, JDBC_URL, "sa", "");
50+
Environment environment = new Environment("test", new JdbcTransactionFactory(), ds);
51+
Configuration config = new Configuration(environment);
52+
config.addMapper(NameTableMapper.class);
53+
sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
54+
} catch (Exception e) {
55+
throw new RuntimeException(e);
56+
}
57+
}
58+
59+
public void insertRecord() {
60+
try (SqlSession session = sqlSessionFactory.openSession(true)) {
61+
NameTableMapper mapper = session.getMapper(NameTableMapper.class);
62+
NameRecord record = new NameRecord();
63+
record.setId(1);
64+
record.setName("Fred");
65+
mapper.insert(record);
66+
}
67+
}
68+
69+
public void updateRecordWithAutoCommit() {
70+
try (SqlSession session = sqlSessionFactory.openSession(true)) {
71+
NameTableMapper mapper = session.getMapper(NameTableMapper.class);
72+
NameRecord record = new NameRecord();
73+
record.setId(1);
74+
record.setName("Barney");
75+
mapper.updateByPrimaryKey(record);
76+
}
77+
}
78+
79+
public void updateRecordWithoutAutoCommitAndNoExplicitCommit() {
80+
// this should rollback
81+
try (SqlSession session = sqlSessionFactory.openSession()) {
82+
NameTableMapper mapper = session.getMapper(NameTableMapper.class);
83+
NameRecord record = new NameRecord();
84+
record.setId(1);
85+
record.setName("Barney");
86+
mapper.updateByPrimaryKey(record);
87+
}
88+
}
89+
90+
public void updateRecordWithoutAutoCommitAndExplicitCommit() {
91+
try (SqlSession session = sqlSessionFactory.openSession()) {
92+
NameTableMapper mapper = session.getMapper(NameTableMapper.class);
93+
NameRecord record = new NameRecord();
94+
record.setId(1);
95+
record.setName("Barney");
96+
mapper.updateByPrimaryKey(record);
97+
session.commit();
98+
}
99+
}
100+
101+
public Optional<NameRecord> getRecord() {
102+
try (SqlSession session = sqlSessionFactory.openSession()) {
103+
NameTableMapper mapper = session.getMapper(NameTableMapper.class);
104+
return mapper.selectByPrimaryKey(1);
105+
}
106+
}
107+
108+
public void resetDatabase() {
109+
try (SqlSession session = sqlSessionFactory.openSession()) {
110+
NameTableMapper mapper = session.getMapper(NameTableMapper.class);
111+
mapper.deleteAll();
112+
}
113+
}
114+
}

src/test/java/issues/gh324/NameTableMapper.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.apache.ibatis.annotations.*;
2222
import org.mybatis.dynamic.sql.BasicColumn;
23+
import org.mybatis.dynamic.sql.delete.DeleteDSLCompleter;
2324
import org.mybatis.dynamic.sql.select.SelectDSLCompleter;
2425
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
2526
import org.mybatis.dynamic.sql.update.UpdateDSLCompleter;
@@ -29,7 +30,7 @@
2930
import java.util.List;
3031
import java.util.Optional;
3132

32-
@CacheNamespace
33+
@CacheNamespace(implementation = ObservableCache.class)
3334
public interface NameTableMapper extends CommonCountMapper, CommonDeleteMapper, CommonInsertMapper<NameRecord>, CommonUpdateMapper {
3435
@SelectProvider(type=SqlProviderAdapter.class, method="select")
3536
@Results(id="NameTableResult", value={
@@ -71,4 +72,8 @@ default int updateByPrimaryKey(NameRecord record) {
7172
.where(id, isEqualTo(record::getId))
7273
);
7374
}
75+
76+
default int deleteAll() {
77+
return MyBatis3Utils.deleteFrom(this::delete, nameTable, DeleteDSLCompleter.allRows());
78+
}
7479
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2016-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package issues.gh324;
17+
18+
import org.apache.ibatis.cache.impl.PerpetualCache;
19+
20+
public class ObservableCache extends PerpetualCache {
21+
22+
private static ObservableCache instance;
23+
24+
public static ObservableCache getInstance() {
25+
return instance;
26+
}
27+
28+
private int requests = 0;
29+
30+
public int getRequests() {
31+
return requests;
32+
}
33+
34+
public int getHits() {
35+
return hits;
36+
}
37+
38+
private int hits = 0;
39+
40+
public ObservableCache(String id) {
41+
super(id);
42+
instance = this;
43+
}
44+
45+
@Override
46+
public void putObject(Object key, Object value) {
47+
super.putObject(key, value);
48+
}
49+
50+
@Override
51+
public Object getObject(Object key) {
52+
Object answer = super.getObject(key);
53+
54+
if (key.toString().contains("select id, name from NameTable where id = ?")) {
55+
requests++;
56+
57+
if (answer != null) {
58+
hits++;
59+
}
60+
}
61+
62+
return answer;
63+
}
64+
65+
@Override
66+
public void clear() {
67+
requests = 0;
68+
hits = 0;
69+
super.clear();
70+
}
71+
}

0 commit comments

Comments
 (0)