事先说明:文章所使用的代码均为书籍赠送的代码,非本人写的。只是在上面做了点注解与解释
package redis;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Set;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.Tuple;
public class chapter4 {
public static final void main(String[] args) {
new chapter4().run();
}
public void run()
{
Jedis conn = new Jedis("localhost");
conn.select(15);
testListItem(conn,false);
testPurchaseItem(conn);
testBenchmarkUpdateToken(conn);
}
public void testListItem(Jedis conn,boolean nested)
{
if(!nested)
System.out.println("\n1.0----- testListItem -----");
System.out.println("1.1We need to set up just enough state so that a user can list an item");
String seller = "userX";
//商品名称
String item = "itemX";
//set在inventory:seller内添加商品名称
conn.sadd("inventory:"+seller,item);
Set<String> iSet = conn.smembers("inventory:"+seller);
System.out.println("The user's inventory has:");
for (String member : iSet){
System.out.println(" " + member);
}
System.out.println();
System.out.println("1.2Listing the item...");
boolean l = listItem(conn, item, seller, 10);
System.out.println("1.3Listing the item succeeded? " + l);
assert l;
//zset从market:中按照从小到达的顺序读取元素
Set<Tuple> r = conn.zrangeWithScores("market:", 0, -1);
System.out.println("The market contains:");
for (Tuple tuple : r){
System.out.println(" " + tuple.getElement() + ", " + tuple.getScore());
}
assert r.size() > 0;
}
public void testPurchaseItem(Jedis conn)
{
System.out.println("\n----- testPurchaseItem -----");
testListItem(conn, true);
System.out.println("We need to set up just enough state so a user can buy an item");
//hash从users:userY中添加{funds[String],value[String]}
conn.hset("users:userY", "funds", "125");
//hash从users:userY中获取其所有的信息{[name,nameAbc],[funds,value]}
Map<String,String> r = conn.hgetAll("users:userY");
System.out.println("The user has some money:");
for (Map.Entry<String,String> entry : r.entrySet()){
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
}
assert r.size() > 0;
assert r.get("funds") != null;
System.out.println();
System.out.println("Let's purchase an item");
boolean p = purchaseItem(conn, "userY", "itemX", "userX", 10);
System.out.println("Purchasing an item succeeded? " + p);
assert p;
r = conn.hgetAll("users:userY");
System.out.println("Their money is now:");
for (Map.Entry<String,String> entry : r.entrySet()){
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
}
assert r.size() > 0;
String buyer = "userY";
Set<String> i = conn.smembers("inventory:" + buyer);
System.out.println("Their inventory is now:");
for (String member : i){
System.out.println(" " + member);
}
assert i.size() > 0;
assert i.contains("itemX");
assert conn.zscore("market:", "itemX.userX") == null;
}
public void testBenchmarkUpdateToken(Jedis conn)
{
System.out.println("\n----- testBenchmarkUpdate -----");
benchmarkUpdateToken(conn, 5);
}
public boolean listItem(Jedis conn,String itemId,String sellerId,double price)
{
String inventory = "inventory:"+sellerId;
String item = itemId+"."+sellerId;
long end = System.currentTimeMillis()+5000;
while(System.currentTimeMillis()<end){
//开启监视用户包裹的变化
conn.watch(inventory);
//如果卖家包裹中的商品不存在的话,则返回false
if(!conn.sismember(inventory, itemId)){
//关闭监视
conn.unwatch();
return false;
}
//开启事务,表示这里的事务是不可打扰的
Transaction transaction = conn.multi();
//zset在market:中添加{item[String],price[double]}
transaction.zadd("market:",price,item);
//set删除inventory:seller中的itemId(商品名称)
transaction.srem(inventory,itemId);
List<Object> result = transaction.exec();
if(result == null){
continue;
}
return true;
}
return false;
}
public boolean purchaseItem(Jedis conn,String buyerId,String itemId,String sellerId,double lprice)
{
String buyer = "users:" + buyerId;
String seller = "users:" + sellerId;
String item = itemId + '.' + sellerId;
String inventory = "inventory:" + buyerId;
long end = System.currentTimeMillis()+10000;
while(System.currentTimeMillis()<end){
conn.watch("market:",buyer);
//zset按照market:中的商品名称{itemA.Id}获取价格
double price = conn.zscore("market:", item);
//hash获取购买者的余额是否足够
double funds = Double.parseDouble(conn.hget(buyer, "funds"));
//如果价格改变了,或者售价高于余额则返回false
if (price != lprice || price > funds){
conn.unwatch();
return false;
}
//开启事务
Transaction trans = conn.multi();
//hash进行买家和卖家之间的钱交易
trans.hincrBy(seller, "funds", (int)price);
trans.hincrBy(buyer, "funds", (int)-price);
//set通过inventory:userId添加用户从库内的物品
trans.sadd(inventory, itemId);
//zset通过market:内删除item商品信息
trans.zrem("market:", item);
//事务执行
List<Object> results = trans.exec();
// null response indicates that the transaction was aborted due to
// the watched key changing.
if (results == null){
continue;
}
return true;
}
return true;
}
public void benchmarkUpdateToken(Jedis conn,int duration)
{
try{
@SuppressWarnings("rawtypes")
Class[] args = new Class[]{
Jedis.class, String.class, String.class, String.class};
Method[] methods = new Method[]{
this.getClass().getDeclaredMethod("updateToken", args),
this.getClass().getDeclaredMethod("updateTokenPipeline", args),
};
for (Method method : methods){
int count = 0;
long start = System.currentTimeMillis();
long end = start + (duration * 1000);
while (System.currentTimeMillis() < end){
count++;
method.invoke(this, conn, "token", "user", "item");
}
long delta = System.currentTimeMillis() - start;
System.out.println(
method.getName() + ' ' +
count + ' ' +
(delta / 1000) + ' ' +
(count / (delta / 1000)));
}
}catch(Exception e){
throw new RuntimeException(e);
}
}
//该函数是使用流水线的pipelined(true/null)
public void updateToken(Jedis conn, String token, String user, String item) {
long timestamp = System.currentTimeMillis() / 1000;
conn.hset("login:", token, user);
conn.zadd("recent:", timestamp, token);
if (item != null) {
conn.zadd("viewed:" + token, timestamp, item);
conn.zremrangeByRank("viewed:" + token, 0, -26);
conn.zincrby("viewed:", -1, item);
}
}
//该函数是不使用流水线的pipelined(false)
public void updateTokenPipeline(Jedis conn, String token, String user, String item) {
long timestamp = System.currentTimeMillis() / 1000;
Pipeline pipe = conn.pipelined();
pipe.multi();
pipe.hset("login:", token, user);
pipe.zadd("recent:", timestamp, token);
if (item != null){
pipe.zadd("viewed:" + token, timestamp, item);
pipe.zremrangeByRank("viewed:" + token, 0, -26);
pipe.zincrby("viewed:", -1, item);
}
pipe.exec();
}
}
运行结果:


本文深入探讨了Redis事务和管道技术的应用,通过具体案例展示了如何利用这些特性提高应用程序的性能。文章首先介绍了如何使用事务来确保数据的一致性和完整性,特别是在商品上架和购买流程中。接着,通过对比两种不同的更新令牌方法,分析了管道技术如何减少网络延迟并提升操作效率。
2977

被折叠的 条评论
为什么被折叠?



