CHƢƠNG 1 : TỔNG QUAN MÔ HÌNH XỬ LÝ GIAO TÁC H-STORE
2.3 Cách thiết kế ứng dụng Voltdb
2.3.2. Thiết kế thủ tục truy nhập dữ liệu (Stored Procedures)
2.3.2.1. Viết thủ tục
Điểm chính của thiết kế truy cập dữ liệu của ứng dụng VoltDB là phải thông qua thủ tục. Nó cũng có thể thực hiện các truy vấn ad hoc trên VoltDB. Tuy nhiên, truy vấn ad hoc phá vỡ hiệu năng tối ưu hóa của VoltDB đã được thiết kết và do đó không nên sử dụng trong code sản phẩm.
Trong VoltDB, Thủ tục và giao dịch là một. Thủ tục thành công hoặc rollback toàn bộ. Bởi vì giao dịch được định nghĩa trước như một thủ tục, do đó không cần phải chỉ rõ BEGIN TRANSACTION và END TRANSACTION.
Với thủ tục, truy cập dữ liệu sử dụng các cấu trúc SQL chuẩn như SELECT, UPDATE, INSERT, và DELETE. Chúng ta cũng có thể thêm các dòng lệnh của mình trong thủ tục để chế biến kết quả trả lại theo ý muốn.
Thủ tục được viết như các lớp Java, mỗi thủ tục là một lớp riêng rẽ.
Ví dụ : Thành phần của một thủ tục VoltDB package fadvisor.procedures; import org.voltdb.*; @ProcInfo( singlePartition = true, partitionInfo = "Reservation.FlightID: 0")
public class HowManySeats extends VoltProcedure { public final SQLStmt GetSeatCount = new SQLStmt(
"SELECT NumOfSeats, COUNT(ReserveID) " + "FROM Flight AS F, Reservation AS R " +
"WHERE F.FlightID=R.FlightID AND R.FlightID=?;"); public long run( int flightid)
throws VoltAbortException { long numofseats;
long seatsinuse;
VoltTable[] queryresults;
voltQueueSQL( GetSeatCount, flightid); queryresults = voltExecuteSQL();
VoltTable result = queryresults[0]; if (result.getRowCount() < 1) { return -1; } numofseats = result.fetchRow(0).getLong(0); seatsinuse = result.fetchRow(0).getLong(1); numofseats = numofseats -seatsinuse; return numofseats; // Return available seats }
}
Thủ tục được viết dưới dạng java classes. Bắt buộc import org.voltdb.*. Chỉ dẫn @ProcInfo nói cho VoltDB là thủ tục đơn vùng hay không. Nếu có, chỉ rõ cột phân vùng. Nếu không singlePartition là true, mặc định VoltDB hiểu là đa vùng.
Thủ tục extends từ class VoltProcedure.
Trong thủ tục, sử dụng các lệnh ANSI SQL chuẩn.
Phương thức Run ném ra ngoại lệ VoltAbortException nên nếu không bắt sẽ gây ra quá trình rollback.
Để thực hiện truy vấn, đặc câu lệnh SQL vào hàng đợi sử dụng phương thức voltQueueSQL.
Sau khi đưa hết các câu lệnh vào hàng đợi. Thực thi sử dụng voltExecuteSQL. Mỗi câu lệnh trả lại một cấu trúc VoltTable. Bởi vì hàng đợi có nhiều truy vấn nên voltExecuteSQL trả lại một mảng cấu VoltTable.
Mã của người dùng nếu muốn.
1. Cấu trúc của thủ tục
• Import org.voltdb.* • Thêm chỉ dẫn @ProcInfo • extends VoltProcedure • Viết code cho phương thức . import org.voltdb.*;
@ProcInfo( singlePartition = true|false,
partitionInfo = "Table-name.Column-name: 0" ) public class Procedure-name extends VoltProcedure { // Declare SQL statements ...
public datatype run ( arguments ) throws VoltAbortException { // Body of the Stored Procedure ...
} }
2. Sử dụng @ProcInfo
Như miêu tả ở trên, một trong các cách đạt được băng thông tối ưu là sử dụng các thủ tục đơn vùng bất cứ khi nào có thể. Sử dụng @ProcInfo.
• partitionInfo chỉ ra cột và giá trị nào được sử dụng cho phân vùng. • singlePartition chỉ ra liệu thủ tục là đơn vùng hay không.
partitionInfo có 3 phần : 2 phần đầu chỉ ra tên của bảng và cột của bảng. Tham số thứ 3 chỉ ra tham số nào của phương thức Run là giá trị cho cột này (đếm từ 0). Nếu tham số thứ = 0 thì tham số đầu tiên của Run dùng cho giá trị cột. Tách tham số thứ 3 với 2 tham số đầu bởi dấu (:).
Ví dụ : @ProcInfo(
singlePartition = true,
partitionInfo = "Reservation.FlightID: 0")
3. Tạo và thực thi truy vấn SQL trong thủ tục
Chức năng chính của thủ tục là thực hiện truy vấn cơ sở dữ liệu. VoltDB thực hiện 2 bước :
1. Truy vấn sử dụng chức năng voltQueueSQL.
2. Thực thi quy vấn và trả lại kết quả voltExecuteSQL. Ví dụ :
public final SQLStmt getcustid = new SQLStmt( "SELECT CustomerID FROM Customer " + "WHERE FirstName=? AND LastName=?;"); ...
voltQueueSQL(getcustid, firstnm, lastnm); VoltTable[] queryresults = voltExecuteSQL();
4. Biên dịch kết quả của truy vấn SQL
Khi gọi voltExecuteSQL, kết quả trả lại một mảng các cấu trúc VoltTable. VoltTable chứa các dòng. Mỗi dòng chứa các cột. Mỗi cột có nhãn và giá trị.
Các phƣơng thức của lớp VoltTable
Method Description
int fetchRow(int index) Trả lại 1 thể hiện của VoltTableRow
int getRowCount() Số row trong bảng
int getColumnCount() Số cột cho mỗi row trong bảng
Type getColumnType(int index) Trả lại kiểu dữ liệu của cột:
BIGINT, DECIMAL, FLOAT, INTEGER, INVALID
NULL, NUMERIC, SMALLINT, STRING, TIMESTAMP, TINYINT, VARBINARY, VOLTTABLE
String getColumnName(int index) Trả lại tên cột double getDouble(int index)
long getLong(int index) String getString(int index) BigDecimal
getDecimalAsBigDecimal(int index)
double getDecimalAsDouble(int index) Date getTimestampAsTimestamp(int index)
long getTimestampAsLong(int index) byte[] getVarbinary(int index)
Bảng 2.4 Các phương thức của lớp VoltTable
5. Trả lại kết quả từ thủ tục
Thủ tục có thể trả lại một VoltTable, một mảng VoltTables, hoặc một giá trị long integer.
6. Rolling Back a Transaction
Cuối cùng, nếu có lỗi xảy ra khi thủ tục thực thi, giao dịch phải rolls back.
2.3.2.2. Khai tắt thủ tục
Thỉnh thoảng chúng ta muốn thực hiện truy vấn đơn và trả lại kết quả tới ứng dụng. Trong những trường hợp đơn giản, viết thủ tục java thật tẻ nhạt. Vì vậy, VoltDB cung cấp một Shotcut.
Thủ tục đơn giản nhất có thể thực thi truy vấn SQL và trả lại kết quả, định nghĩa toàn bộ thủ tục như là một phần của file định nghĩa dự án.
<procedure class="procedures.simple.FetchReservations" partitioninfo="Reservation.flightid:0">
<sql>SELECT * FROM RESERVATION WHERE FLIGHTID=? </sql> </procedure>