如何使用datastax Java对象映射将the example given here映射到下面的类?
public class User {
private int user;
private int balance;
private List<Bill> bills;
}
public class Bill {
private String description;
private int amount;
}
答案 0 :(得分:3)
关于java驱动程序中的映射模块,静态列不需要与非静态列进行任何不同的处理。但是,您需要考虑的一个问题是,只有当余额是预期值时才需要更新余额,因此单独使用Mapper的保存方法是不够的。相反,您将使用余额的条件更新进行批处理,并在同一批次中使用费用进行更新。
为了方便并仍然使用Mapper,您可以使用Accessor-annotated interface来定义查询并将它们映射回您的对象。然后,您可以使用mapper对象和其他一些方法创建一个数据访问对象,以便与Cassandra连接。
这需要一些工作,但我认为它为您提供了一个很好的清洁方法,可以将您的解决方案从Cassandra中抽象出来,同时仍然以惯用的方式使用它。另一个选择是查看Achilles,它是Cassandra的一个更高级的对象持久性管理器。 Kundera和Spring Data是其他可能的选择。
首先,让我们看一下您的类,并将它们映射到博客示例中定义的表:
CREATE TABLE bills (
user text,
balance int static,
expense_id int,
amount int,
description text,
paid boolean,
PRIMARY KEY (user, expense_id)
);
从您的示例中,我怀疑您可能希望使用用户定义的类型而不是单独的列用于帐单,但是因为您标记了此帖子&cassandra-2.0&#39;并且直到2.1才会引入UDT,我不会对此进行介绍,但如果您希望我能够详细说明,我可以。
让我们定义我们的班级Bill
:
@Table(name="bills")
public class Bill {
@PartitionKey
private String user;
private int balance;
@ClusteringColumn
@Column(name="expense_id")
private int expenseId;
private int amount;
private String description;
private boolean paid;
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public int getExpenseId() {
return expenseId;
}
public void setExpenseId(int expenseId) {
this.expenseId = expenseId;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isPaid() {
return paid;
}
public void setPaid(boolean paid) {
this.paid = paid;
}
}
让我们定义一个BillAccessor
,用于在cassandra中与我们的Bills交互,将它们映射回Bill
个对象。这应该涵盖博客文章中的所有查询:
@Accessor
public interface BillAccessor {
@Query("INSERT INTO bills (user, balance) VALUES (?, ?) IF NOT EXISTS")
BoundStatement addUser(String user, int balance);
@Query("UPDATE bills SET balance = :newBalance WHERE user = :user IF balance = :currentBalance")
BoundStatement updateBalance(@Param("user") String user, @Param("currentBalance") int currentBalance,
@Param("newBalance") int newBalance);
@Query("SELECT balance from bills where user=?")
ResultSet getBalance(String user);
@Query("INSERT INTO bills (user, expense_id, amount, description, paid) values (?, ?, ?, ?, false) IF NOT EXISTS")
BoundStatement addBill(String user, int expenseId, int amount, String description);
@Query("UPDATE bills set paid=true where user=? and expense_id=? IF paid=false")
BoundStatement markBillPaid(String user, int expenseId);
@Query("SELECT * from bills where user=?")
Result<Bill> getBills(String user);
}
接下来,我们将使用Bill
课程和BillAccessor
创建一个与您的帐单进行接口的DAO:
public class BillDao {
private final Session session;
private final Mapper<Bill> mapper;
private final BillAccessor accessor;
public BillDao(Session session) {
this.session = session;
MappingManager manager = new MappingManager(session);
this.mapper = manager.mapper(Bill.class);
this.accessor = manager.createAccessor(BillAccessor.class);
}
public Integer getBalance(String user) {
ResultSet result = accessor.getBalance(user);
Row row = result.one();
if(row == null) {
return null;
} else {
return row.getInt(0);
}
}
public Iterable<Bill> getBills(String user) {
return accessor.getBills(user);
}
public Bill getBill(String user, int expenseId) {
return mapper.get(user, expenseId);
}
public int addBill(String user, int expenseId, int amount, String description) throws UpdateException {
BatchStatement batch = new BatchStatement();
Integer balance = getBalance(user);
if (balance == null) {
balance = 0;
// we need to create the user.
batch.add(accessor.addUser(user, balance - amount));
} else {
// we need to update the users balance.
batch.add(accessor.updateBalance(user, balance, balance - amount));
}
batch.add(accessor.addBill(user, expenseId, amount, description));
ResultSet result = session.execute(batch);
if (result.wasApplied()) {
return balance - amount;
} else {
throw new UpdateException("Failed applying bill, conditional update failed.");
}
}
public int payForBill(Bill bill) throws UpdateException {
Integer balance = getBalance(bill.getUser());
if(balance == null) {
throw new UpdateException("Failed paying for bill, user doesn't exist!");
}
BatchStatement batch = new BatchStatement();
batch.add(accessor.updateBalance(bill.getUser(), balance, bill.getAmount() + balance));
batch.add(accessor.markBillPaid(bill.getUser(), bill.getExpenseId()));
ResultSet result = session.execute(batch);
if(result.wasApplied()) {
return bill.getAmount() + balance;
} else {
throw new UpdateException("Failed paying for bill, conditional update failed.");
}
}
public class UpdateException extends Exception {
public UpdateException(String msg) {
super(msg);
}
}
}
请注意,我们会检查ResultSet.wasApplied()来检查是否应用了更改。由于我们正在进行条件更新,因此如果我们的条件不成立,则可能无法应用更改。如果没有应用更改,DAO将简单地抛出UpdateException
,但您可以选择不同的策略,例如在DAO中重试任意次数。
最后让我们编写一些代码来练习DAO:
Cluster cluster = Cluster.builder().addContactPoint("127.0.0.1").build();
try {
Session session = cluster.connect("readtest");
BillDao billDao = new BillDao(session);
String user = "chandru";
// Create a bill, should exercise user create logic.
int balance = billDao.addBill(user, 1, 10, "Sandwich");
System.out.format("Bill %s/%d created, current balance is %d.%n", user, 1, balance);
// Create another bill, should exercise balance update logic.
balance = billDao.addBill(user, 2, 6, "Salad");
System.out.format("Bill %s/%d created, current balance is %d.%n", user, 2, balance);
// Pay for all the bills!
for(Bill bill : billDao.getBills(user)) {
balance = billDao.payForBill(bill);
System.out.format("Paid for %s/%d, current balance is %d.%n", user, bill.getExpenseId(), balance);
// Ensure bill was paid.
Bill newBill = billDao.getBill(user, bill.getExpenseId());
System.out.format("Is %s/%d paid for?: %b.%n", user, newBill.getExpenseId(), newBill.isPaid());
}
// Try to add another bill with an already used expense id.
try {
billDao.addBill(user, 1, 1, "Diet Coke");
} catch(BillDao.UpdateException ex) {
System.err.format("Could not add bill %s/%d: %s", user, 1, ex.getMessage());
}
} finally {
cluster.close();
}
如果一切顺利,您应该观察以下输出:
Bill chandru/1 created, current balance is -10.
Bill chandru/2 created, current balance is -16.
Paid for chandru/1, current balance is -6.
Is chandru/1 paid for?: true.
Paid for chandru/2, current balance is 0.
Is chandru/2 paid for?: true.
Could not add bill chandru/1: Failed applying bill, conditional update failed.
你的桌子的状态将是:
cqlsh:readtest> select * from bills;
user | expense_id | balance | amount | description | paid
---------+------------+---------+--------+-------------+------
chandru | 1 | 0 | 10 | Sandwich | True
chandru | 2 | 0 | 6 | Salad | True