1. Trang chủ
  2. » Công Nghệ Thông Tin

Just Spring Data Access ppt

76 1,7K 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Just Spring Data Access
Tác giả Madhusudhan Konda
Trường học O'Reilly Media, Inc.
Năm xuất bản 2012
Thành phố Beijing, Cambridge, Farnham, Köln, Sebastopol, Tokyo, United States
Định dạng
Số trang 76
Dung lượng 6,53 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

However, the steps involved in using a JDBC are always the same—obtain a connection,create a Statement, execute a query, run it through ResultSet, and release the resources.The following

Trang 3

Just Spring Data Access

Madhusudhan Konda

Trang 4

Just Spring Data Access

by Madhusudhan Konda

Copyright © 2012 Madhusudhan Konda All rights reserved.

Printed in the United States of America.

Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472 O’Reilly books may be purchased for educational, business, or sales promotional use Online editions are also available for most titles (http://my.safaribooksonline.com) For more information, contact our corporate/institutional sales department: 800-998-9938 or corporate@oreilly.com.

Editors: Mike Loukides and Meghan Blanchette

Production Editor: Iris Febres

Copyeditor: Gillian McGarvey

Proofreader: Iris Febres

Interior Designer: David Futato

Illustrator: Robert Romano

Revision History for the First Edition:

2012-06-01 First release

See http://oreilly.com/catalog/errata.csp?isbn=9781449328382 for release details.

Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of

O’Reilly Media, Inc Just Spring Data Access, the image of the channel-billed cuckoo, and related trade

dress are trademarks of O’Reilly Media, Inc.

Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a trademark claim, the designations have been printed in caps or initial caps.

While every precaution has been taken in the preparation of this book, the publisher and authors assume

no responsibility for errors or omissions, or for damages resulting from the use of the information tained herein.

con-ISBN: 978-1-449-32838-2

Trang 5

Table of Contents

Foreword v Preface vii

Trang 6

Using Spring Hibernate 31

Trang 7

Reading headlines like “Facebook moves 30-petabyte Hadoop cluster to new data ter” shows that one of the biggest struggles we are facing today is Big Data and itsmanagement Data centric applications, mobile front ends to complex data structures,and serving millions of clients accessing our datasets while handling billions of trans-actions a day shows that keeping data management simple and easy to handle is a firstclass problem in modern application development

cen-Thankfully, tools like Spring Data and it’s many utilities make it easy to access thesedata sets using whichever flavor of standards best fits our team’s skills and needs WhileJava blazed the trail by offering the flexible but consistent JDBC standard, it was thepower of Spring that cut out the tedious amounts of boilerplate afforded to us by his-torical SQL paradigms This has empowered developers to focus on business logic,scaling requirements, mobile platform support, and other numerous requirementswhile allowing Spring to handle the chores of managing connections and interactingwith various data management technologies This is analogous to migrating from themanual memory management of coding in C to Java’s sophisticated garbage collection,which removed a whole host of bugs we as developers used to face every day By re-ducing the total amount of code we must write to access our own Big Data, we quicklycut out a huge number of potential bugs on Day One of our own projects

It is refreshing to read a slim and trim book like Just Spring Data Access, which avoids

the ever popular thick-as-possible approach and instead tries to be as clear and point as possible For the fledgling developer that has just joined a team that uses SpringData, this book provides a fantastic means to “catch up” over the weekend and be ready

to-the-to dive in on Monday For an architect trying to-the-to choose which standard to-the-to use for anew system, it also provides a quick read, allowing him or her to start their evaluationwith something more concrete than some cobbled together opinions Finally, for themore seasoned developer, it provides a good reference to look back and polish up skills

in the arena of data management and the options provided by competing Java ards None of us are experts on everything, and having a tightly focused book is oftenjust what we need to hone in and solve the problems we have

stand-—Greg Turnquist, Senior Software Engineer at SpringSource, a division of VMware,

and author of Spring Python 1.1

Trang 9

There are two different worlds: the world where none other than objects are known,and the world where data is represented in a traditional row-column format Bringingthese two worlds together is always a cumbersome task, and many times is asking fortrouble However, we have no option: they must work together!

We have JDBC to some extent, but the intricacies and complexities of persistence ofJava objects to a relational databases was still a greater challenge The Object RelationalMapping frameworks—Hibernate being the most popular open source framework—has taken away a lot of pain and grief from the developer Spring framework has goneone more step further to simplify the usage even further

This book in an attempt in bringing the framework closer to the developer With simpleand plain language, along with easy to understand examples, this book covers just therequired bits for data access in a Java world

This book covers JDBC, Hibernate, JPA, and JDO, as well as Spring’s take on thesetechnologies

My goal is to deliver simple, straight-to-the-point explanations with intuitive, driven, engaging books! If you pick up the book, you should finish it in a day or two

pre-If you are in London, ping me (and perhaps buy me a coffee) for a meetup Additionally,

I am easily accessible via email (madhusudhan@madhusudhan.com) or via Twitter(@mkonda007)

Trang 10

Conventions Used in This Book

The following typographical conventions are used in this book:

Constant width bold

Shows commands or other text that should be typed literally by the user

Constant width italic

Shows text that should be replaced with user-supplied values or by values mined by context

deter-This icon signifies a tip, suggestion, or general note.

This icon indicates a warning or caution.

Using Code Examples

This book is here to help you get your job done In general, you may use the code inthis book in your programs and documentation You do not need to contact us forpermission unless you’re reproducing a significant portion of the code For example,writing a program that uses several chunks of code from this book does not requirepermission Selling or distributing a CD-ROM of examples from O’Reilly books doesrequire permission Answering a question by citing this book and quoting examplecode does not require permission Incorporating a significant amount of example codefrom this book into your product’s documentation does require permission

We appreciate, but do not require, attribution An attribution usually includes the title,

author, publisher, and ISBN For example: “Just Spring Data Access by Madhusudhan

Konda (O’Reilly) Copyright 2012 Madhusudhan Konda, 978-1-449-32838-2.”

If you feel your use of code examples falls outside fair use or the permission given above,feel free to contact us at permissions@oreilly.com

Trang 11

Safari® Books Online

Safari Books Online (www.safaribooksonline.com) is an on-demand digitallibrary that delivers expert content in both book and video form from theworld’s leading authors in technology and business

Technology professionals, software developers, web designers, and business and ative professionals use Safari Books Online as their primary resource for research,problem solving, learning, and certification training

cre-Safari Books Online offers a range of product mixes and pricing programs for zations, government agencies, and individuals Subscribers have access to thousands

organi-of books, training videos, and prepublication manuscripts in one fully searchable tabase from publishers like O’Reilly Media, Prentice Hall Professional, Addison-WesleyProfessional, Microsoft Press, Sams, Que, Peachpit Press, Focal Press, Cisco Press, JohnWiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FTPress, Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett, Course Tech-nology, and dozens more For more information about Safari Books Online, please visit

Find us on Facebook: http://facebook.com/oreilly

Follow us on Twitter: http://twitter.com/oreillymedia

Watch us on YouTube: http://www.youtube.com/oreillymedia

Trang 12

I also thank my family in India for their wonderful support and love.

This book was written in memory of my loving Dad—we all miss you, Dad!

Trang 13

CHAPTER 1 Basics

Persistence of data is a challenging task for developers There are many things that could

go wrong The introduction of JDBC has given the developer community a bit of joy

by taking away painstakingly cumbersome database access in Java applications ever, there are a few wrinkles that come with JDBC, such as having to write boilerplatecode, finding out a clue from the SQLExcetion stacktrace, resource management, and

How-so on

Spring has gone further in simplifying the data access by providing a simple andstraightforward framework This chapter discusses Spring’s take on JDBC, and howSpring simplified the JDBC programming model; it did so by employing simple yetpowerful mechanisms, such as Dependency Injection, Templates, and other patterns

Using Plain JDBC

With the advent of JDBC, accessing data from a Java application has become relativelyeasy Not only do we have independence from database vendor lock-in, but we alsohave a standard API to access multitude of databases

However, the steps involved in using a JDBC are always the same—obtain a connection,create a Statement, execute a query, run it through ResultSet, and release the resources.The following code demonstrates a simple example of selecting the TRADES data usingplain JDBC:

public class JdbcPlainTest {

private String DB_URL="jdbc:mysql://localhost:3306/JSDATA";

private final String USER_NAME = "XXXX";

private final String PASSWORD = "XXXX";

private Connection createConnection() {

Connection conn = null;

try {

Class.forName("com.mysql.jdbc.Driver");

conn =

Trang 14

public static void main(String args[]) {

JdbcPlainTest t = new JdbcPlainTest();

• The SQLException must be caught in both the creation and destruction processes

• The actual business logic is not more than a couple of lines; unfortunately, code iscluttered with lot of JDBC API statements and calls

We can create a home-grown framework with callbacks and handlers to resolve theseissues Although it does work, creating your own framework leads to several issues—maintenance, extending to suit newer requirements, extensive testing, and others

Trang 15

If there’s already a framework that does this work, why reinvent the wheel?

The Spring data access framework is specifically created to address these problems It

is a beautiful framework that promotes Dependency Injection principles and carries

multiple features

Spring Data Access

The Spring data access framework has made the developer’s job very easy!

It creates a rich framework in which, or from which to access databases by decoupling

our code from the access mechanisms As always, the framework heavily uses ency Injection patterns, so decoupling of our code really comes to life The components

Depend-using framework’s API are easily testable, too Moreover, there’s no exceptions that weshould have to catch when using the APIs!

The access logic revolves around Template patterns and Support classes These patterns

hide away all the boilerplate code and allows the developer to concentrate solely onbusiness logic

Templates

From the previous example, we can see that there is a lot of code that’s not central tobusiness function It would be ideal to wrap up the non-critical code away from ourbusiness code in a separate class Spring’s JdbcTemplate class does exactly that.This class wraps up all the access logic so users only need to concentrate on the heart

of the application If you understand the workings of JdbcTemplate, I would say you’veconquered most of Spring’s data access workings

In addition to the standard JdbcTemplate, there are two other variations of the Templateclass: SimpleJdbcTemplate and NamedParameterJdbcTemplate These two varieties arenothing but wrappers around JdbcTemplate that are used for special cases We willdiscuss all of these in the coming sections Before we work out examples, we have tocarry out some prerequisites such as creating a database schema and prepopulating testdata

If you already have a database in place, you can skip this section without any concern

MySQL Database Scripts

I am using MySQL as the database for all of the examples provided in this book Setting

up the database is easy if you follow the instructions from the provider carefully.Once you have MySQL set up, make sure you run the SQL scripts provided by thebook’s source code These scripts will create a database called JSDATA and create nec-essary tables such as ACCOUNTS, TRADES, PRICES, and others If you are working with some

Trang 16

other database, you should be able to run the scripts without any issues; personally, Ihave not tested them.

The next important thing is to create a DataSource The DataSource encapsulates thedatabase provider information and hence acts like a connection factory by fetchingconnections to talk to the database It should be created by driver information such asURL, username, password, and other information Make sure that you supply the nec-essary provider (driver) information to construct a DataSource if you are using any otherdatabases

The datasource-beans.xml file shown below creates a DataSource for MySQL database:

<bean id="mySqlDataSource" class="org.apache.commons.dbcp.BasicDataSource"

destroy-method="close">

<property name="driverClassName" value="com.mysql.jdbc.Driver" />

<property name="url" value="jdbc:mysql://localhost:3306/JSDATA" />

</bean>

The class attribute points to an implementor of the DataSource interface; in the abovesnippet, it is a BasicDataSource class from Apache Common’s DBCP project ThedriverClassName points to a class that will be specific to a database

We will see the full definition in a minute

Throughout the book, we will use DBCP datasource, which can be downloaded fromthe site: http://commons.apache.org/dbcp/ If you are using Maven, add the snippet to

your pom.xml file (check out the full pom.xml provided with the book’s source code)

to include DBCP and MySQL connector jars:

Trang 17

resources, which leads to lots of issues JdbcTemplate comes to our rescue in doing thehouse cleaning job for us!

Before we work with JdbcTemplate, we must set the DataSource first This is a mandatoryrequirement that JdbcTemplate be configured with a DataSource object so the templatewill be able to create connections and statements behind the scenes

Configuring a DataSource

As we have already seen, the javax.sql.DataSource is an interface that determines theconnection details for a particular provider Each provider will have their own imple-mentation of the class, usually provided in a Jar file The MySQL driver class is defined

by the com.mysql.jdbc.Driver class, for example

The following configuration shows how to set up a data source for MySQL:

<bean id="mySqlDataSource" class="org.apache.commons.dbcp.BasicDataSource">

<property name="driverClassName" value="com.mysql.jdbc.Driver"/>

<property name="url" value="jdbc:mysql://localhost:3306/JSDATA"/>

<property name="username" value="jsuser"/>

<property name="password" value="jsuser"/>

</bean>

</beans>

The above snippet will create a bean named mySqlDataSource that points to a MySQLdatabase running on localhost, directed by the url property If we are using other pro-viders, we need to create another bean with the same properties, but with appropriatevalues relevant to our provider

Trang 18

Let’s see an example of instantiating JdbcTemplate with a preconfigured DataSource.

public class JdbcTemplateTest {

private ApplicationContext ctx = null;

private JdbcTemplate template = null;

private DataSource datasource = null;

// Instantiate the template with the datasource

template = new JdbcTemplate(datasource);

}

public static void main(String[] args) {

JdbcTemplateTest t = new JdbcTemplateTest();

// execute the data access methods from here

}

}

The steps are simple:

• Load and fetch the context from a config file that consists of datasources (in our

case, it’s the datasouces-beans.xml)

• Create the JdbcTemplate using the new operator providing the datasource bean toits constructor

Once you have the JdbcTemplate fully configured and functional, you are ready to use

it to access our databast tables The JdbcTemplate has a lot of functionality that requires

a bit of detail study

Working with JdbcTemplate

The JdbcTemplate has more than 100 methods that give varied access to data sets!For example, you may wish to execute straight queries such as inserting data or creatingtables You can use the execute() method exposed on the JdbcTemplate for such actions.Likewise, if you wish to query for single or multiple data rows, you should be usingqueryForXXX methods There are lots of other methods, some of them are self explana-tory and others are easy to follow using JavaDoc We will cover the most important ofall of these methods in the coming sections

Let’s say our requirement is to find out the number ofrows present in the TRADES table

Querying for Single and Multiple Rows.

Trang 19

The following snippet shows the usage of JdbcTemplate in its simplest form—for ing the number of TRADES in the table:

fetch-public int getTradesCount(){

You can also rewrite the above example by using the more generic queryForObjectmethod However, the method takes a second parameter, which basically describes thereturn value’s data type In our example, because count(*) will return an integer, wepass the Integer class to the method call

This is illustrated below:

public int getTradesCount(){

int numOfTrades =

template.queryForObject("select count(*) from TRADES",Integer.class);

return numOfTrades;

}

// Another example of get the max id of the

// trade using queryForObject method

public int getTradeMaxId(){

int maxId =

template.queryForObject("select max(id) from TRADES", Integer.class);

return maxId;

}

The above snippet also provides another example of using the queryForObject method

to query for a Trade that has a maximum id The queryForLong and queryForStringfollow the same pattern, returning a Long and String value, respectively

The queryForMap returns a single row in a Map<String,Object> format as shown below:

public Map<String,Object> getTradeAsMap(){

// note that we have hardcoded ID here!

Trang 20

//The output to the console is:

Trades Map:{ID=1, ACCOUNT=1234AAA, SECURITY=MDMD,

QUANTITY=100000, STATUS=NEW, DIRECTION=BUY}

As you can see, each column name is the key represented by String while the value isrepresented by the Object in the Map<String,Object> declaration

However, the queryForList is a bit different to others in that it can return multiple rows.The rows are returned as a List of Map<String,Object> format

Let’s see this at work The getAllTrades() method fetches all of the trades and printsout to the console:

public List<Map<String,Object>> getAllTrades(){

{ID=5, ACCOUNT=452SEVE, STATUS=NEW, DIRECTION=SELL}]

The queries that we used in the above examples are fairly simple We can also writecomplex queries that can be executed in the same fashion We often use where clausesand other SQL constructs to execute complex queries However, the where clause re-quires input variables to be set How can we parameterize these bind variables?

Bind variables help to create a dynamic SQL query If our requirement is

to fetch records based on various conditions, we usually use the where clause in ourSQL script Bind variables are the preferred option as opposed to using inline variablesbecause they protect our application against SQL injection attacks

For example, if we have to get the STATUS of a Trade whose id is 5, we need to write theSQL as follows:

public String getTradeStatus(int id){

String status =

template.queryForObject("select STATUS from TRADES where id= ?",

new Object[]{id}, String.class);

return status;

}

Bind Variables.

Trang 21

The ? will be an indication to the framework to substitute the value with the secondparameter of the method, which in the above case is the id The way to do this is tocreate an array of Object with your incoming id value The third parameter is the type

of value the method query is expected to return; in this case, the STATUS is a String type

We can provide more than a one bind variable, no restriction on the number

In the following snippet, the overloaded getTradeStatus() method has two conditions

in the where clause and accordingly, we provide a second value via a second parameter,Object array:

public String getTradeStatus(int id, String security){

We know that each row in the TRADES table is represented

by our Trade domain object Although we have seen fetching the Trades from the table,

we have not yet seen how we create a Trade object from each row of the record

In order to do this, we need to use a RowMapper callback provided by the framework.The RowMapper interface has one method—mapRow—where you need to map the in-coming row to the domain object You can create the RowMapper as an anonymous class

or you can have your own class implementing the RowMapper interface separately.Let’s take a look at each one separately

First, we create a TradeMapper class that implements the RowMapper interface and definesits single method:

private static final class TradeMapper implements RowMapper<Trade>{

@Override

public Trade mapRow(ResultSet rs, int rowNum) throws SQLException {

Trade t = new Trade();

// set the values by use ResultSet's getXXX methods

As we now have our RowMapper implementation ready, we give it to the overloadedqueryForObject method to retrieve all the trades from the table:

Mapping Rows to Domain Objects.

Trang 22

public Trade getMappedTrade(int id){

Trade trade = template.queryForObject("select * from TRADES where id = ?",

There’s an alternative way of using RowMapper—we can also use an anonymous class tocreate a RowMapper instead of creating a separate instance as we have seen above Theway to do so is illustrated below:

public Trade getTrade(int id){

Trade trade = template.queryForObject("select * from TRADES where id= ?",

new Object[]{id},

new RowMapper<Trade>(){

@Override

public Trade mapRow(ResultSet rs, int row) throws SQLException {

Trade t = new Trade();

Creating the RowMapper class anonymously has a limited scope—it can’t be used where else in the application Unless you have a strong case to use the anonymous class,

any-go with a separate class like TradeMapper and reuse it Reusability scores good marks!Note that both the JdbcTemplate and RowMapper classes are thread safe You can sharethem and use them across threads without having to worry about state corruption

Now that we know how to fetch a single record and map to a main object, let’s see how to get the list of all rows mapped to domain objects Actually,

do-it is qudo-ite straight forward now that you have a RowMapper class already designed

Fetching List of Trades.

Trang 23

The following snippet is used to fetch such a list Note that the only change was usingquery() method rather than queryForXXX method:

public List<Trade> getAllMappedTrades(){

Inserting, Deleting, and Updating Rows

We also use the JdbcTemplate to do the updates We use JdbcTemplate.update() variants

to execute the appropriate statements The following snippet shows inserting a Tradeinto TRADES table:

private void insertTrade() {

There is a way You can use the another variant of the update method that takes varargs:

private void updateTrade(String status, int id) {

int rowsUpdated =

template.update("update TRADES set status=? where id=?",status, id);

Trang 24

System.out.println("Rows Updated:"+rowsUpdated);

}

There’s another overloaded method that sets the bind variables using an Object array(which we have already seen in our query examples earlier) and java.sql.Types array.The types array will provide the necessary framework tools to typecast the variables

In the following updateTradeUsingTypes method, we are using the types array to let theframework know the bind values type However, as the status and id are already knowntypes, perhaps using the types array might not be needed except for the compiler’s sake

private void updateTradeUsingTypes(String status, int id) {

int rowsUpdated = template.update(

"update TRADES set status=? where id=?",

new Object[] { status, id },

new int[] { java.sql.Types.VARCHAR, java.sql.Types.INTEGER });

System.out.println("Rows Updated:" + rowsUpdated);

int rowsUpdated = template.update(

"update TRADES set status=? where id=?",

new Object[] { "UNKNOWN","6" },

new int[] { java.sql.Types.VARCHAR,java.sql.Types.INTEGER });

System.out.println("Rows Updated:" + rowsUpdated);

}

You can also invoke a Stored Procedure using the update method, as shown here:

private void replayTradesUsingSP(List tradeIds) {

public void createAndDropPersonTable(){

template.execute("create table PERSON

(FIRST_NAME varchar(50) not null, LAST_NAME varchar(50) not null)");

// drop the table

template.execute("drop table PERSON");

Trang 25

up the unnecessary boilerplate code into templates We have seen the fundamentalclass of the framework—JdbcTemplate—in action We learned how to utilize the classusing simple examples.

The next chapter will discuss the additional templates along with advanced SpringJDBC usage using Support classes and callbacks

Trang 27

CHAPTER 2 Advanced Concepts

The Spring framework has provided extensive APIs to work with the database We’vecovered the basics of the framework in the last chapter, especially using the versatileJdbcTemplate class This chapter elaborates on advanced concepts, including othertemplates, callbacks, and batch operations

NamedParameterJdbcTemplate

In our queries, we define the bind variables using a ? operator as shown in the followingsnippet:

select count(*) from TRADES

where account = ? and security = ?

If we have a handful of these parameters, it would be an eyesore to read a querywith ? all over the place Spring has defined a new NamedParameterJdbcTemplate classthat comes handy in eliminating these placeholder variables This class basically en-capsulates the JdbcTemplate by providing the enhanced functionality of declaring thebind variables using named parameters

The same query can be tweaked as shown below using appropriate names instead

of ? variables:

select count(*) from TRADES

where account = :account and security = :security

The :account and :security names indicate that these variables will be passed in bysome means Note the colon (:) before the variable; this is the syntax you must follow.There are two ways of setting these variables One is to use a simple Map with the vari-ables as the keys, and the other is to use SqlParameterSource, a utility provided by theframework

Trang 28

Using Map

The following snippet shows how to set the variables by using a map with keys:

public int getTradesCount(String s, String a){

Map bindValues = new HashMap();

bindValues.put("status", s);

bindValues.put("account", a);

int numOfTrades = template.queryForInt

("select count(*) from TRADES where account=:account and status=:status",

bindValues);

System.out.println("Number of Trades: "+numOfTrades);

return numOfTrades;

}

In the above example, we populate the Map with the provided arguments setting them

to the status and account keys Then we pass this Map to the query Did you noticethe names in the query? The names declared in the query must match the keys of ourMap

Using SqlParameterSource

The second way of setting the bind variables is by using framework’s helper interface,SqlParameterSource There’s an out-of-box implementation available in the form ofMapSqlParameterSource which acts as a wrapper around Map The way to set values is

to use the addValue() method and chain them as shown below:

public int getTradesCountUsingSqlParameterSource(String s, String a){

SqlParameterSource bindValues =

new MapSqlParameterSource().addValue("status", s).addValue("account", a);

int numOfTrades = template.queryForInt

("select count(*) from TRADES

where account=:account and status=:status", bindValues);

.

}

There is another implementation of the same interface which works on extracting thevalues from a Java object that complies to JavaBean standards The BeanPropertySql ParameterSource takes an instance and finds the values of the properties See the fol-lowing example to understand the usage:

public int getTradesCountUsingBeanSqlParameterSource(Trade t){

SqlParameterSource bindValues = new BeanPropertySqlParameterSource(t);

int numOfTrades = template.queryForInt

("select count(*) from TRADES where account=:account and status=:status", bindValues);

}

The class browses through the Trade object to find the respective properties—in ourcase, status and account The following snippet shows the way to call the method Thequery will use the account 1234AAAA and status NEW as the arguments retrieved from theTrade bean

Trang 29

public static void main(String[] args) {

NamedParameterJdbcTemplateTest t = new NamedParameterJdbcTemplateTest();

Trade trade = new Trade();

replac-Jdbc Batching

Executing lots of updates or inserts one after another is a cumbersome operation If

your JDBC Driver supports, batching is an excellent strategy for improving mance For example, if you wish to insert 10,000 trades, you can insert them in a batchsize of 100, 500, 1,000, or any other number The JDBC statement will be re-used whenexecuting the batch instead of creating new statements every time you execute a call to

perfor-a dperfor-atperfor-abperfor-ase operperfor-ation Another perfor-advperfor-antperfor-age is thperfor-at the round trips to the dperfor-atperfor-abperfor-ase (usuperfor-allyover the network) are drastically reduced

Both JdbcTemplate and NamedParameterJdbcTemplate provide support for batch tions Again, there are couple of ways of doing this: using the framework’s utility classSqlParameterSourceUtils or extending the framework’s BatchPreparedStatementSet ter interface

execu-Using SqlParameterSourceUtils

The SqlParameterSourceUtils is a handy utility class the converts the List to an array

of SqlParameterSource instances

The snippet shown below shows how we use it in action:

private int[] insertTradesList(final List<Trade> trades) {

SqlParameterSource[] tradesList =

SqlParameterSourceUtils.createBatch(trades.toArray());

int[] updatesCount = namedTemplate.batchUpdate(

"insert into TRADES values

(:id,:account,:security,:quantity,:status,:direction)",

tradesList);

return updatesCount;

}

Trang 30

You pass in a List of Trades that will be converted to an array of SqlParameterSource bythe SqlParameterSourceUtils utility class This array is then passed to our template forexecution, which returns the rows that were inserted into database.

private int[] insertTrades(final List<Trade> trades) {

int[] updatesCount = template.batchUpdate(

"insert into TRADES values(?,?,?,?,?,?)",

In the above example, the setValues() method will be invoked ten times This method

is similar to the one used for getBatchSize(), which utilizes the samePreparedStatement for all the calls This is an improvement

How would you go about updating larger bucket of trades, such as 100,000 of them?Instead of using the above strategy of calling the insertTrades with different batch sizes,Spring provides you with another version of the batchUpdate method In this instance,

it takes a batch size—say you wish to batch those hundred thousand trades into a batch

of 1,000—which is passed in to the method as a second parameter The addition is aParameterizedPreparedStatementSetter class that implements the setValues() methodsetting values from each Trade on the PreparedStatement

Trang 31

public void setValues(PreparedStatement ps, Trade t) throws SQLException { ps.setInt(1, t.getId());

state-Let’s see them at work

SimpleJDBCInsert Class

The SimpleJDBCInsert class is used to execute inserts with minimalistic configuration.The first thing you need to do is to instantiate the class with a DataSource and set thetable name by invoking the method withTableName()

The following example shows this:

private SimpleJdbcInsert jdbcInsert = null;

// Get the datasource

datasource = ctx.getBean("mySqlDataSource", DataSource.class);

//Create the instance associating with the table

jdbcInsert = new SimpleJdbcInsert(datasource).withTableName("TRADES");

Now that the object is ready, we invoke the execute() method that takes a Trade Thevalues of the trade are set against the key values of a Map and passed to theSimpleJdbcInsert class:

public void insertTrade(Trade t) {

Map tradeMap = new HashMap();

Trang 32

Make sure the keys match the column names That’s it—no SQL statements and nomore placeholders!

Should you wish to insert only one or two columns, you can set the column namesusing the usingColumns() method as shown below:

The following snippet summarizes it in this context:

public void insertTradeUsingSqlParameterSource(Trade t) {

// create an instance passing our Trade object

SqlParameterSource source = new BeanPropertySqlParameterSource(t);

The trade_by_quantity is a Stored Procedure that fetches a big trade whose quantity

is provided by the client It takes the quantity as IN parameter and spits out ID andACCOUNT values of the row as OUT parameters for the matching big trade

CREATE PROCEDURE trade_by_quantity

(IN in_qty INTEGER, OUT big_trade_id INTEGER)

in-jdbcCall = new SimpleJdbcCall(datasource)

withProcedureName("trade_by_quantity");

Trang 33

Now that we have our class configured, we need to work on the method that invokesthis class.

The method shown below does exactly that: it creates an instance of SqlParameter Source with quantity as the bind value and invokes the execute method on the class

public Trade getBigTradeUsingSimpleJdbcCall(String quantity){

SqlParameterSource inValues =

new MapSqlParameterSource().addValue("quantity", quantity);

Map bigTrades = jdbcCall.execute(inValues);

Trade t = new Trade();

t.setId((Integer)bigTrades.get("id"));

t.setAccount((String)bigTrades.get("account"));

return t;

}

The execute method returns a Map with the declared OUT parameters as the keys What

we do is to fetch them from the map based on the OUT parameters and set them on tothe Trade object

The above program returns only one Trade You can also use SimpleJdbcCall to invoke

a StoredProc that returns a ResultSet Create the class as shown below, passing aRowMapper implementation—ParameterizedBeanPropertyRowMapper in this case

jdbcCall = new SimpleJdbcCall(datasource)

withProcedureName("big_trades")

returningResultSet("trades", new ParameterizedBeanPropertyRowMapper());

Map bigTrades = jdbcCall.execute();

develop-to Derby, it carries a fundamental difference: Oracle (Java provider) supports andmaintains the Java DB while Derby is maintained outside the Java ecosystem by Apachegroup

The inner workings of these databases are similar to the Relational Database ment Systems (RDBMS) that we know We can see how Spring helps us in developingaccess to Java DB

Trang 34

Manage-The first thing we need to do is to create a DataSource It follows the same lines tonormal DataSource definitions—make sure you provide the right driver class and URLs.Take the following, for example:

<property name="username" value="" />

<property name="password" value="" />

</bean>

As we see in the above snippet, defining an in-memory DataSource is no different toother types of RDBMS DataSources The url points to the local file system path wherethe database will be created The appending create=true string at the end of the urlindicates if the database (in this case JSDATA) should be created if it does not exist.Ideally, the first time you start your Java DB, leave this as true (and turn it to false later

on or else the driver throws warnings!) so the schema will be created for us

The next step is to create our JdbcTemplate using this injected DataSource as we havealready seen in many earlier cases The following snippet shows this test scenario:

public class JavaDBTest {

private ApplicationContext ctx = null;

private JdbcTemplate template = null;

private DataSource datasource = null;

// Create our template using JavaDB DataSource

template = new JdbcTemplate(datasource);

}

//Insert a trade

private void insertTrade() {

int rowsUpdated = template.update(

"insert into TRADES values(?,?,?,?,?,?)", 33, "JSDATA", "REV",500000, "NEW",

"SELL");

System.out.println("Rows Updated:" + rowsUpdated);

}

public static void main(String[] args) {

JavaDBTest test = new JavaDBTest();

test.insertTrade();

}

}

Trang 35

In-memory databases are quite useful in development mode; it really gears up the ductivity to a certain degree We do not have to change our SQL scripts when we releaseour code to production; only the DataSource definition needs to be changed Addition-ally, it will not point to a production-RDBMS.

pro-Callbacks

As you may have already noticed, there are two parts in any JDBC client program: onepart gets the connection, creates the statement, and deals with resource management,which is more or less a boilerplate code The other part is the heart of the applicationwhere we code the business logic

The framework hides away the nonbusiness code efficiently in the templates whileallowing us to concentrate on the business logic It does this by providing valuablecallbacks where we can deal with writing the business logic

We have already seen a RowMapper callback in action earlier Let’s see the rest of them,such as RowCallbackHandler, PreparedStatementCallback, and CallableStatementCall back here

PreparedStatement Callback

Should you have a requirement to run the code in your own PreparedStatement, rely

on this callback

The framework will ideally create one and hands over to you via the callback

There are two ways to get the handle to the PreparedStatement: one is by creating yourown implementation class and the other is by creating an anonymous class

Let’s say we need to extract a Map of Trade id and Trade account from our TRADES tableusing the PreparedStatement route To do this, we must create a class and implementthe framework’s PreparedStatementCallback interface to override the doInPrepared Statement method

The following is the code snippet for the callback that executes the query in a givenPrepatedStatement, which results in a ResultSet object The Id and Account columnvalues are extracted from the resultSet into the Map object

private class PSCallback implements

PreparedStatementCallback<Map<Integer, Object>> {

Map<Integer, Object> tradeIdAccountsMap =

new HashMap<Integer, Object>();

@Override

public Map<Integer, Object> doInPreparedStatement(PreparedStatement ps)

throws SQLException, DataAccessException {

ResultSet rs = ps.executeQuery();

while (rs.next()) {

Trang 36

int tradeId = rs.getInt(1);

String account = rs.getString(2);

public void getTradesMapViaPSCallback() throws Exception {

Map<Integer, Object> tradeIdAccountsMap =

template.execute("select * from TRADES", new PSCallback());

System.out.println("ID-ACCOUNTS map:" + tradeIdAccountsMap);

}

Alternatively, you can also declare your callback inline:

public void getTradePSCallbackAsAnonymous() throws Exception {

Trade t = template.execute("select * from TRADES where id=1",

new PreparedStatementCallback<Trade>() {

private Trade t = new Trade();

@Override

public Trade doInPreparedStatement(PreparedStatement ps)

throws SQLException, DataAccessException {

As you can see, we extracted one Trade from the ResultSet and returned it

I mentioned earlier that the PreparedStatement that was given to our implementors werealready pre-configured with a SQL statement

What if we wish to create the SQL query somewhere else? It turns out that Spring hasthought of this and hence provides PreparedStatementCreator interface This meansthe implementation will create a statement from the connection provided

The following snippet is the implementor of this interface The example shows that wewere given a Connection object to create a PreparedStatement using the SQL query

class PSCreator implements PreparedStatementCreator {

@Override

public PreparedStatement createPreparedStatement(Connection con)

throws SQLException {

Trang 37

// Provide the creator and callback

Map<Integer, Object> tradeIdAccountsMap =

template.execute(new PSCreator(), new PSCallback());

System.out.println("ID-ACCOUNTS map:" + tradeIdAccountsMap);

}

Callable Statement Callbacks

The framework provides a couple of callbacks for CallableStatements: the CallableS tatementCallback and CallableStatementCreator classes

Fortunately, they follow exactly the same footsteps as PreparedStatementXXX For ample, you have to implement CallableStatementCallback to define the doInCalla bleStatement method, wherein you would be given CallableStatement instead:

ex-public void testCSCallbackViaCreator() throws Exception {

Map<Integer, Object> tradeIdAccountsMap = template.execute(

"select * from TRADES", new CSCallback());

System.out.println("ID-ACCOUNTS map:" + tradeIdAccountsMap);

}

private class CSCallback implements CallableStatementCallback {

@Override

public Object doInCallableStatement(CallableStatement ps)

throws SQLException, DataAccessException {

Trang 38

The following snippet shows this:

class BigTradeCounter implements RowCallbackHandler {

The following code shows the invocation:

private void bigTradeCountHanlder(double quantity) {

BigTradeCounter counter = new BigTradeCounter(quantity);

template.query("select * from TRADES", counter);

System.out.println("Big Trades" + counter.getBigTradeCount());

}

You can also define the same class as an anonymous inline class

Note that the RowMapper class that we learned about in the first chapter does the samething The RowCallbackHandler implementation holds onto state and hence can’t be re-used unless a new instance is created

Ngày đăng: 06/03/2014, 23:20

TỪ KHÓA LIÊN QUAN