Skip to content

Commit 14cd22f

Browse files
authored
Support 'multi()' from JedisPooled (UnifiedJedis) (#3361)
1 parent d45b31a commit 14cd22f

File tree

8 files changed

+122
-4
lines changed

8 files changed

+122
-4
lines changed

src/main/java/redis/clients/jedis/JedisCluster.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,4 +209,13 @@ public Connection getConnectionFromSlot(int slot) {
209209
public ClusterPipeline pipelined() {
210210
return new ClusterPipeline((ClusterConnectionProvider) provider);
211211
}
212+
213+
/**
214+
* @return nothing
215+
* @throws UnsupportedOperationException
216+
*/
217+
@Override
218+
public Transaction multi() {
219+
throw new UnsupportedOperationException();
220+
}
212221
}

src/main/java/redis/clients/jedis/JedisSharding.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,13 @@ public JedisSharding(ShardedConnectionProvider provider, Pattern tagPattern) {
4444
public ShardedPipeline pipelined() {
4545
return new ShardedPipeline((ShardedConnectionProvider) provider);
4646
}
47+
48+
/**
49+
* @return nothing
50+
* @throws UnsupportedOperationException
51+
*/
52+
@Override
53+
public Transaction multi() {
54+
throw new UnsupportedOperationException();
55+
}
4756
}

src/main/java/redis/clients/jedis/ReliableTransaction.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class ReliableTransaction extends TransactionBase {
1515
* Creates a new transaction.
1616
*
1717
* A MULTI command will be executed. WATCH/UNWATCH/MULTI commands must not be called with this object.
18+
* @param connection connection
1819
*/
1920
public ReliableTransaction(Connection connection) {
2021
super(connection);
@@ -33,6 +34,20 @@ public ReliableTransaction(Connection connection, boolean doMulti) {
3334
super(connection, doMulti);
3435
}
3536

37+
/**
38+
* Creates a new transaction.
39+
*
40+
* A user wanting to WATCH/UNWATCH keys followed by a call to MULTI ({@link #multi()}) it should
41+
* be {@code doMulti=false}.
42+
*
43+
* @param connection connection
44+
* @param doMulti {@code false} should be set to enable manual WATCH, UNWATCH and MULTI
45+
* @param closeConnection should the 'connection' be closed when 'close()' is called?
46+
*/
47+
public ReliableTransaction(Connection connection, boolean doMulti, boolean closeConnection) {
48+
super(connection, doMulti, closeConnection);
49+
}
50+
3651
@Override
3752
protected final void processMultiResponse() {
3853
String status = connection.getStatusCodeReply();

src/main/java/redis/clients/jedis/Transaction.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public Transaction(Jedis jedis) {
2121
*
2222
* A MULTI command will be added to be sent to server. WATCH/UNWATCH/MULTI commands must not be
2323
* called with this object.
24+
* @param connection connection
2425
*/
2526
public Transaction(Connection connection) {
2627
super(connection);
@@ -41,6 +42,21 @@ public Transaction(Connection connection, boolean doMulti) {
4142
this.jedis = null;
4243
}
4344

45+
/**
46+
* Creates a new transaction.
47+
*
48+
* A user wanting to WATCH/UNWATCH keys followed by a call to MULTI ({@link #multi()}) it should
49+
* be {@code doMulti=false}.
50+
*
51+
* @param connection connection
52+
* @param doMulti {@code false} should be set to enable manual WATCH, UNWATCH and MULTI
53+
* @param closeConnection should the 'connection' be closed when 'close()' is called?
54+
*/
55+
public Transaction(Connection connection, boolean doMulti, boolean closeConnection) {
56+
super(connection, doMulti, closeConnection);
57+
this.jedis = null;
58+
}
59+
4460
@Override
4561
protected final void processMultiResponse() {
4662
// do nothing

src/main/java/redis/clients/jedis/TransactionBase.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public abstract class TransactionBase extends Queable implements PipelineCommand
4040
PipelineBinaryCommands, RedisModulePipelineCommands, Closeable {
4141

4242
protected final Connection connection;
43+
private final boolean closeConnection;
4344
private final CommandObjects commandObjects;
4445
private final GraphCommandObjects graphCommandObjects;
4546

@@ -52,6 +53,7 @@ public abstract class TransactionBase extends Queable implements PipelineCommand
5253
*
5354
* A MULTI command will be added to be sent to server. WATCH/UNWATCH/MULTI commands must not be
5455
* called with this object.
56+
* @param connection connection
5557
*/
5658
public TransactionBase(Connection connection) {
5759
this(connection, true);
@@ -67,7 +69,22 @@ public TransactionBase(Connection connection) {
6769
* @param doMulti {@code false} should be set to enable manual WATCH, UNWATCH and MULTI
6870
*/
6971
public TransactionBase(Connection connection, boolean doMulti) {
72+
this(connection, doMulti, false);
73+
}
74+
75+
/**
76+
* Creates a new transaction.
77+
*
78+
* A user wanting to WATCH/UNWATCH keys followed by a call to MULTI ({@link #multi()}) it should
79+
* be {@code doMulti=false}.
80+
*
81+
* @param connection connection
82+
* @param doMulti {@code false} should be set to enable manual WATCH, UNWATCH and MULTI
83+
* @param closeConnection should the 'connection' be closed when 'close()' is called?
84+
*/
85+
public TransactionBase(Connection connection, boolean doMulti, boolean closeConnection) {
7086
this.connection = connection;
87+
this.closeConnection = closeConnection;
7188
this.commandObjects = new CommandObjects();
7289
this.graphCommandObjects = new GraphCommandObjects(this.connection);
7390
if (doMulti) multi();
@@ -112,7 +129,13 @@ protected final <T> Response<T> appendCommand(CommandObject<T> commandObject) {
112129

113130
@Override
114131
public final void close() {
115-
clear();
132+
try {
133+
clear();
134+
} finally {
135+
if (closeConnection) {
136+
connection.close();
137+
}
138+
}
116139
}
117140

118141
public final void clear() {

src/main/java/redis/clients/jedis/UnifiedJedis.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4649,8 +4649,14 @@ public Object pipelined() {
46494649
if (provider == null) {
46504650
throw new IllegalStateException("It is not allowed to create Pipeline from this " + getClass());
46514651
}
4652-
Connection connection = provider.getConnection();
4653-
return new Pipeline(connection, true);
4652+
return new Pipeline(provider.getConnection(), true);
4653+
}
4654+
4655+
public Transaction multi() {
4656+
if (provider == null) {
4657+
throw new IllegalStateException("It is not allowed to create Pipeline from this " + getClass());
4658+
}
4659+
return new Transaction(provider.getConnection(), true, true);
46544660
}
46554661

46564662
public Object sendCommand(ProtocolCommand cmd) {

src/test/java/redis/clients/jedis/ClusterPipeliningTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,4 +1044,11 @@ public void simple() { // TODO: move into 'redis.clients.jedis.commands.unified.
10441044
}
10451045
}
10461046
}
1047+
1048+
@Test
1049+
public void transaction() {
1050+
try (JedisCluster cluster = new JedisCluster(nodes, DEFAULT_CLIENT_CONFIG)) {
1051+
assertThrows(UnsupportedOperationException.class, () -> cluster.multi());
1052+
}
1053+
}
10471054
}

src/test/java/redis/clients/jedis/commands/unified/pooled/PooledPipelinedTest.java renamed to src/test/java/redis/clients/jedis/commands/unified/pooled/PooledPipeliningTest.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@
1414
import redis.clients.jedis.JedisPooled;
1515
import redis.clients.jedis.Pipeline;
1616
import redis.clients.jedis.Response;
17+
import redis.clients.jedis.Transaction;
1718

1819
import redis.clients.jedis.commands.unified.UnifiedJedisCommandsTestBase;
1920

20-
public class PooledPipelinedTest extends UnifiedJedisCommandsTestBase {
21+
public class PooledPipeliningTest extends UnifiedJedisCommandsTestBase {
2122

2223
protected Pipeline pipeline;
24+
protected Transaction transaction;
2325

2426
@BeforeClass
2527
public static void prepare() throws InterruptedException {
@@ -35,11 +37,13 @@ public static void cleanUp() {
3537
public void setUp() {
3638
PooledCommandsTestHelper.clearData();
3739
pipeline = ((JedisPooled) jedis).pipelined();
40+
transaction = jedis.multi();
3841
}
3942

4043
@After
4144
public void tearDown() {
4245
pipeline.close();
46+
transaction.close();
4347
}
4448

4549
@Test
@@ -71,4 +75,33 @@ public void simple() {
7175
assertEquals(expected.get(i), responses.get(i).get());
7276
}
7377
}
78+
79+
@Test
80+
public void transaction() {
81+
final int count = 10;
82+
int totalCount = 0;
83+
for (int i = 0; i < count; i++) {
84+
jedis.set("foo" + i, "bar" + i);
85+
}
86+
totalCount += count;
87+
for (int i = 0; i < count; i++) {
88+
jedis.rpush("foobar" + i, "foo" + i, "bar" + i);
89+
}
90+
totalCount += count;
91+
92+
List<Object> expected = new ArrayList<>(totalCount);
93+
for (int i = 0; i < count; i++) {
94+
transaction.get("foo" + i);
95+
expected.add("bar" + i);
96+
}
97+
for (int i = 0; i < count; i++) {
98+
transaction.lrange("foobar" + i, 0, -1);
99+
expected.add(Arrays.asList("foo" + i, "bar" + i));
100+
}
101+
102+
List<Object> responses = transaction.exec();
103+
for (int i = 0; i < totalCount; i++) {
104+
assertEquals(expected.get(i), responses.get(i));
105+
}
106+
}
74107
}

0 commit comments

Comments
 (0)