Java III
This presentation is the property of its rightful owner.
Sponsored Links
1 / 58

Java III PowerPoint PPT Presentation


  • 128 Views
  • Uploaded on
  • Presentation posted in: General

Java III. Mastering Transactions In Java. Transactions: Basics. Transactions: Basics. • In the world of programming a Transaction is a series of actions that must occur as a group. • If any portion of the group of actions fails, the entire Transaction fails.

Download Presentation

Java III

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Java iii

Java III


Java iii

Mastering Transactions

In Java


Java iii

Transactions:

Basics


Java iii

Transactions: Basics

• In the world of programming a Transaction is a series of actions that must occur as a group.

• If any portion of the group of actions fails, the entire Transaction fails.

This lecture is based in part on the book Java Transaction Design Strategies by Mark Richards.

This lecture is based in part onJava Transaction Processing by Mark Little, Jon Maron and Greg Pavlik.


Java iii

Transactions: Basics

• A.C.I.D. is the well-known acronym for the characteristics of a successful and valid transaction.

• Atomicity

• Consistency

• Isolation

• Durability

These principles were first described

by James Gray in the late 1970s and in

1983 the acronym A.C.I.D. was coined

by Andreas Reuter and Theo Härder.


Java iii

Transactions: Basics

• Atomicity—follows the metaphor of the “Atom”.

• You cannot have half an atom.

• If a transaction does not complete perfectly, it gets undone and the database should be left in a state as if nothing at all ever happened.


Java iii

Transactions: Basics

• Consistency—change must take the database from one consistent state before the transaction started to another consistent state after the transaction has finished.

• Referential integrity must be maintained.

• The data meets all rules for validation.

• Numeric fields must only hold numeric data, etc.


Java iii

Transactions: Basics

• Isolation—by its nature a transaction consists of several small steps. All the intermediate steps must be completed before the entire transaction can be called complete.

• While the transaction is in progress but not yet complete, the in-progress changes must be hidden or isolated from the rest of the database and other transactions.

• If I deduct money from the checking account and then deposit that money in the savings account, the checking deduction must not be visible to anyone until the transaction is done.


Java iii

Transactions: Basics

• Durability—once a transaction is deemed complete, the transaction will not be lost.

• Don’t announce success until everything is committed.

• Transaction Log—a common strategy used to back up the contents of the transaction.


Java iii

Transactions:

Local Transactions


Java iii

Transactions: Local Transactions

• A Local Transaction is a punt.

• We let the database handle our transactions entirely.

• This works fine if our Logical Unit of Work [LUW] consists of exactly one query.

• Not exactly what we have in mind when we think of a “transaction”.


Java iii

Transactions: Local Transactions

• If we want to do two things, such as subtract from a savings account and deposit into a checking account, a Local Database transaction is not much help.

• If we subtract $100 from the savings account and then the system crashes before we get the deposit done—we just lost $100.

• So, already, we have reached the end of the usefulness of a database-local transaction.

• Java offers several ways to help us out.


Java iii

Transactions:

Gotchas In Java


Java iii

Transactions: Gotchas In Java

• In the Java world we are fortunate to have great APIs such as the JTA (Java Transaction API)

• Thanks to Rod Johnson, we have the

wonderful Spring Framework.

• After the horror story that was EJB2.1

Entity beans, JPA was a reason to pump your fist in joy.

• Thanks to EJB 3.0, we have some great frameworks that take away all the peril of using transactions… right?


Java iii

Transactions: Gotchas In Java

• Consider this simple code. It runs flawlessly.

• So this JPA code will happily insert the deposit and return the idof the generated row, right?

public class JpaBankServiceImpl

{

@PersistenceContext(unitName=“bank”) EntityManager entityMan;

public long makeDeposit( Deposit deposit ) throws Exception

{

entityMan.persist( deposit );

return deposit.getDepositId();

}

}


Java iii

Transactions: Gotchas In Java

• Consider this simple code. It runs flawlessly.

• So this code will happily insert the deposit and return the idof the generated row, right?

• Nope! It won’t throw an exception, will return 0 and leave the databaseuntouched. It won’t do a damn thing!

public class JpaBankServiceImpl

{

@PersistenceContext(unitName=“bank”) EntityManager entityMan;

public long makeDeposit( Deposit deposit ) throws Exception

{

entityMan.persist( deposit );

return deposit.getDepositId();

}

}


Java iii

Transactions: Gotchas In Java

• What? The newbie asks. “What went wrong?”

• Nothing. For this to work you have to wrap it in a transaction.

• But it won’t tell you anything is wrong.

public class JpaBankServiceImpl

{

@PersistenceContext(unitName=“bank”) EntityManager entityMan;

public long makeDeposit( Deposit deposit ) throws Exception

{

entityMan.persist( deposit );

return deposit.getDepositId();

}

}


Java iii

Transactions: Gotchas In Java

• Your changes were placed in the L1object cache.

• But only a transactiontells JPA to synchronize its object cache with the database.


Java iii

Sidebar: What is the Object Cache?

  • When an object and its dependencies are pulled from the database, it may require several queries.

  • The L1 transaction Object Cache is part of every EnityManagerand is not shared.

  • Not to be confused with the L2 shared cache, stored in the EntityManagerFactory, which is visible to all EnityManagers.

  • EachEnityManagerkeeps its ownObject Cache.


Java iii

Transactions: Gotchas In Java

• In JPA, when you persistan object, it only writes the object to its Object Cache.

• JPA onlywrites its object to the database upon the commitof a transaction.

• So, no transaction =no commit.


Java iii

Transactions:

Gotchas In Java: Spring


Java iii

Transactions: Gotchas In Java: Spring

• Spring does a lot for us but we still need to think and understand.

• Remember there are two broad categories:

programmatic transactions

declarative transactions

• Using programmatictransactions, we have to code everything.

• Using declarativetransactions, we add an annotationto our code and a framework such as Spring does the rest, right?


Java iii

Transactions: Gotchas In Java: Spring

• In the case of Spring, our declarative model asks us to provide an annotation such as @Transactional.

public class SpringBankServiceImpl

{

@PersistenceContext(unitName=“bank”) EntityManager entityMan;

@Transactional

public long makeDeposit( Deposit deposit ) throws Exception

{

entityMan.persist( deposit );

return deposit.getDepositId();

}

}

• You test it again and no error, no exception and no change to the DB.


Java iii

Transactions: Gotchas In Java: Spring

• The problem is, like with all things Spring, you need to update the Spring configuration file.

<tx:annotation-driven transaction-manager=“transactionManager” />

• So, transactionManagermust be a Spring bean that is defined elsewhere in your Spring configuration file.

• Spring will implement this using a cool Spring feature called an interceptorthat in turn will use another annotation, @Transaction.


Java iii

Transactions: Gotchas In Java: Spring

• Okay—sweet—now we’re good.

<tx:annotation-driven transaction-manager=“transactionManager” />

public class SpringBankServiceImpl

{

@PersistenceContext(unitName=“bank”) EntityManager entityMan;

@Transactional

public long makeDeposit( Deposit deposit ) throws Exception

{

entityMan.persist( deposit );

return deposit.getDepositId();

}

}

• But wait a second. There are a lot of choices involved in setting up a transaction. We’re using the defaults here.


Java iii

Transactions: Gotchas In Java: Spring

• When we use @Transactional by itself with no parameters, what are the default values for things like propagation mode, the read-only flag and transaction isolation?

• Most importantly, what happens when we need to roll back?


Java iii

Transactions: Gotchas In Java: Spring

• When we use a bare @Transactional, the default values make it as if we had written this:

• Most importantly, the transaction will not roll back on a checked exception.

@Transactional( read-only=false, propagation=REQUIRED, isolation-level=READ_COMMITTED )


Java iii

Transactions: Gotchas In Java: Spring

• Here’s a great example from Mark Richards:

@Transactional(readOnly=true, propagation=Propagation.SUPPORTS)

public long insertDeposit( Deposit deposit ) throws Exception

{

// JDBC insert code

}

• Notice this is read-only. So, what happens?

A. It throws a read-only connection exception.

B. It inserts the deposit and commits the data.

C. It does nothing because the propagation level says supports and there is no transaction to support.


Java iii

Transactions: Gotchas In Java: Spring

• Here’s a great example from Mark Richards:

@Transactional(readOnly=true, propagation=Propagation.SUPPORTS)

public long insertDeposit( Deposit deposit ) throws Exception

{

// JDBC insert code

}

• Notice this is read-only. So, what happens?

A. It throws a read-only connection exception.

B. It inserts the deposit and commits the data.

C. It does nothing because the propagation level says supports and there is no transaction to support.

WTF?


Java iii

Transactions: Gotchas In Java: Spring

@Transactional(readOnly=true, propagation=Propagation.SUPPORTS)

public long insertDeposit( Deposit deposit ) throws Exception

{

// JDBC insert code

}

• B. It inserts the deposit and commits the data.

• The read-only flag is only honored when there is a transaction. Since it’s SUPPORTS and there was no already-started transaction to support, it never got one.

• The JDBC code used a local (database) transaction and committed the code.


Java iii

Transactions: Gotchas In Java: Spring

• Okay, what if we make the Propagation REQUIRED?

@Transactional(readOnly=true, propagation=Propagation.REQUIRED)

public long insertDeposit( Deposit deposit ) throws Exception

{

// JDBC insert code

}

A. It throws a read-only connection exception.

B. It inserts the deposit and commits the data.

C. It does nothing because the readOnly flag is set to true.


Java iii

Transactions: Gotchas In Java: Spring

• Okay, what if we make the Propagation REQUIRED?

@Transactional(readOnly=true, propagation=Propagation.REQUIRED)

public long insertDeposit( Deposit deposit ) throws Exception

{

// JDBC insert code

}

A. It throws a read-only connection exception.

B. It inserts the deposit and commits the data.

C. It does nothing because the readOnly flag is set to true.

• Because there was a transaction [REQUIRED], the readOnly flag was honored.


Java iii

Transactions: Gotchas In Java: Spring

• There are a lot of hidden problems with all of the various propagation modes and you need to be very careful.


Java iii

Transactions: Gotchas In Java: Spring

• Next, I asked: what happens when you need a roll back?

@Transactional(propagation=Propagation.REQUIRED)

public long transferCash( Transfer transfer) throws Exception

{

try

{

deductFromSavings( transfer );

depositIntoChecking( transfer );

return tranfer.getTransactionId();

}

catch( Exception e )

{

// log error

throw e;

}

}

• What if depositIntoChecking() throws a checked Exception? Does everything get rolled back?


Java iii

Transactions: Gotchas In Java: Spring

• No! The update from deductFromSavings() is committed!

@Transactional(propagation=Propagation.REQUIRED)

public long transferCash( Transfer transfer) throws Exception

{

try

{

deductFromSavings( transfer );

depositIntoChecking( transfer );

return tranfer.getTransactionId();

}

catch( Exception e )

{

// log error

throw e;

}

}


Java iii

Transactions: Gotchas In Java: Spring

• In this scenario ( using default values) for both Spring and EJB 3, only runtime(unchecked) exceptions cause the transaction to roll back.

• When you code your annotation like this, the transaction will NOT roll back for any checked exception.

@Transactional(propagation=Propagation.REQUIRED)

• Why on earth would Spring or EJB be set up that way?

• The explanation is that there might be some exceptions that you can recover from. So, to not preclude that alternative, they are set up this way.


Java iii

Transactions: Gotchas In Java: Spring

• So, the take away in Spring declarative transactions is that you must specify which checked exceptions warrant a roll back.

@Transactional(propagation=Propagation.REQUIRED, rollbackFor=SQLException.class)

@Transactional(propagation=Propagation.REQUIRED, rollbackFor=SQLException.class)

• The rollbackForparameter takes either a single exception or an array of them.

• There is another alternative rollbackForClassNameand yet another for noRollbackFor.


Java iii

Transactions:

3 Alternative Models


Java iii

Transactions: 3 Alternative Models

•There are three broad approaches to doing transactions in Java.

• These are known as “Transaction Models”.

 Local (database) Transactions

 Programmatic Transactions

 Declarative Transactions


Java iii

Transactions: 3 Alternative Models: Local

• Local (database) Transactions are an abdication on the part of the Java tier.

• The database does 100% of the work.

• The Connection is the closest you get can to the transactions.

• By turning off the setAutoCommit( false ); in your Java code you can achieve ACID over several database actions and by then calling either commit() at the end or rollback(); in the case of an Exception.


Java iii

Transactions: 3 Alternative Models: Programmatic

• With Programmatic Transactionsyou write program logic to manage the transactions.

• Instead of managing the Connection, you manage the transaction from your Java code.


Java iii

Transactions: 3 Alternative Models: Programmatic Spring

public class SpringProgrammaticTransaction

{

@PersistenceContext(unitName=“banking”) EntityManager em;

JpaTransactionManager transManager= null;

public void doTransfer( TransactionValues modifications )

{

TransactionStatus ts = jtm.getTransaction( new DefaultTransactionDefinition() );

try

{

em.persist( modifications );

AcctState acctState = em.find( AcctState.class, modifications.getTransactionId() );

applyTransactionModifications( acctState, modifications );

em.persist( acctState );

transManager.commit( ts );

}

catch( Exception e )

{

transManager.rollback(ts );

}

}

// Spring injected

public void setTransManager( JpaTransactionManager transManager )

{

this.transManager = transManager;

}

}


Java iii

Transactions: 3 Alternative Models: Declarative

• With Declarative Transactions you signal your wishes for the transaction and rely on your understanding of the nuances of the annotations and their various attribute values.

• Another name for CMT—Container-Managed Transactions.

• Spring uses the @Transactional attribute.

• EJB 3.0 uses @TransactionAttribute.

• In declarative transactions automatic roll-back is not a given after a checked exception occurs.


Java iii

Transactions: 3 Alternative Models: Declarative EJB3

@Stateless

public class EJB30DeclarativeBankingServiceimplements BankingService

{

@PersistenceContext(unitName=“banking”) EntityManager em;

@Resource SessionContextctx;

@TransactionalAttribute( TransactionAttributeType.REQUIRED )

public void transferMoney( Transfer transfer ) throws Exception

{

try

{

AcctInfoacctInfo = em.find( AccountInfo.class, transfer.getTransferId();

if( transferAcceptible( acctInfo, transfer ) )

{

em.persist( transfer );

em.persist( acctInfo );

}

}

catch( Exception e )

{

ctx.setRollbackOnly();

}

}

}


Java iii

Transactions: 3 Alternative Models: Declarative Spring

public class SpringDeclarativeBankingService

{

@PersistenceContext(unitName=“banking”) EntityManager em;

@Transactional( propagation=Propagation.REQUIRED, rollbackFor=Exception.class )

public void transferMoney( Transfer transfer ) throws Exceptio

{

em.persist( transfer );

AcctDataacctData = em.find( AcctData.class, transfer.getTransferId() );

if( accountAgreesWithTransfer( transfer, acctData ) )

{

acctData.applyTransfer( transfer );

}

}

}


Java iii

Transactions:

High Concurrency Strategies


Java iii

Transactions: High Concurrency Strategies

• For many concurrent transactions, the transaction strategy changes.

• If your transactions take too long, you shorten the transaction.

• You remove operations such as reads and processing that do not need to be transactional.


Java iii

Transactions: High Concurrency Strategies

• Naked reads—you read a value without a transaction—even though you are planning to update it.

• Another write could have gotten in there right after your read and then you would lose that update.

• Each read gets a version stamp and then after your optimistic read you trust but verify and compare the version stamp.


Java iii

Transactions: High Concurrency Strategies: Not!

@Stateless

@Remote(BankingService.class)

public class BankingServiceImpl implements BankingService

{

@Resource SessionContextctx;

@PersistenceContext( unitName=“banking” ) EntityManager em;

@TransactionAttribute(TransactionAttributeType.REQUIRED)

public void transferMoney( Transfer transfer ) throws Exception

{

try

{

AccountHolder holder = em.find( AccountHolder.class, transfer.getAccountId() );

Withdrawlwithdrawl = sourceAccountContainsSufficientFunds( holder, transfer )

if( withdrawl != null )

{

em.persist( withdrawl );

verifySpamBeingSent( holder );

verifyAddressSentToCatalogCompanies( holder );

verifyAccountIsEligibleForOverdraftProtection( holder );

verifySentEmailOfferingToStopSpam( holder );

Deposit deposit = buildDepositFromTransfer( holder, transfer );

em.persist( deposit );

}

}

catch( Exception e )

{

ctx.setRollbackOnly();

}

}

}


Java iii

Transactions: High Concurrency Strategies: Not!

@Stateless

@Remote(BankingService.class)

public class BankingServiceImpl implements BankingService

{

@Resource SessionContextctx;

@PersistenceContext( unitName=“banking” ) EntityManager em;

@TransactionAttribute(TransactionAttributeType.REQUIRED)

public void transferMoney( Transfer transfer ) throws Exception

{

try

{

AccountHolder holder = em.find( AccountHolder.class, transfer.getAccountId() );

Withdrawlwithdrawl = sourceAccountContainsSufficientFunds( holder, transfer )

if( withdrawl != null )

{

em.persist( withdrawl );

verifySpamBeingSent( holder );

verifyAddressSentToCatalogCompanies( holder );

verifyAccountIsEligibleForOverdraftProtection( holder );

verifySentEmailOfferingToStopSpam( holder );

Deposit deposit = buildDepositFromTransfer( holder, transfer );

em.persist( deposit );

}

}

catch( Exception e )

{

ctx.setRollbackOnly();

}

}

}

Everything in black is included in the transaction. Bad!


Java iii

Transactions: High Concurrency Strategies: Yes!

public void transferMoney( Transfer transfer ) throws Exception

{

UserTransactiontxn= null;

try

{

AccountHolder holder = service.getAccountHolder( transfer.getAccountId() );

verifySpamBeingSent( holder );

verifyAddressSentToCatalogCompanies( holder );

verifyAccountIsEligibleForOverdraftProtection( holder );

verifySentEmailOfferingToStopSpam( holder );

Withdrawlwithdrawl= sourceAccountContainsSufficientFunds( holder, transfer );

Deposit deposit = buildDepositFromTransfer( holder, transfer );

txn= (UserTransaction) ctx.lookup( “UserTransaction” );

txn.begin();

service.makeWithdrawl( withdrawl );

service.makeDeposit( deposit );

txn.commit();

}

catch( Exception e )

{

if( txn != null )

{

txn.rollback();

}

}

}


Java iii

Transactions: High Concurrency Strategies: Yes!

public void transferMoney( Transfer transfer ) throws Exception

{

UserTransactiontxn= null;

try

{

AccountHolder holder = service.getAccountHolder( transfer.getAccountId() );

verifySpamBeingSent( holder );

verifyAddressSentToCatalogCompanies( holder );

verifyAccountIsEligibleForOverdraftProtection( holder );

verifySentEmailOfferingToStopSpam( holder );

Withdrawlwithdrawl= sourceAccountContainsSufficientFunds( holder, transfer );

Deposit deposit = buildDepositFromTransfer( holder, transfer );

txn= (UserTransaction) ctx.lookup( “UserTransaction” );

txn.begin();

service.makeWithdrawl( withdrawl );

service.makeDeposit( deposit );

txn.commit();

}

catch( Exception e )

{

if( txn != null )

{

txn.rollback();

}

}

}

Everything in black is included in the transaction. Better!


Java iii

Transactions:

High Performance Strategies


Java iii

Transactions: High Performance Strategies

• If your goal is high performance, then there is a bag of techniques.

• You abandon any transaction management in the Java layer.

• You revert to local transactions managed 100% by the DB.

• No transaction-guaranteed ACID across multiple queries


Java iii

Transactions: High Performance Strategies

• Each read, update, delete rides in its own transaction that commits at the end of each statement.

• It uses a Compensation Strategy.

• A Compensation Strategy keeps track of the transaction steps that were committed.

• In case of an error, the Compensation Strategyreversesthe transaction steps to undothe committed steps.

• No transaction Isolation—data is sharedinstantly.


Java iii

Transactions: High Performance Strategies

• J2EE Activity Service for Extended Transactions (JSR 95) can serve as a Compensation Strategy framework.

• JBoss Business Activity Framework


Java iii

public class TradingService

{

private CompController compController = new CompController();

private AcctDAO acctDao = new AcctDAO();

private TradeDAO tradeDao = new TradeDAO();

public void processTrade(TradeData trade) throws Exception

{

String compId = UUID.randomUUID().toString();

try

{

//start the compensation scope compController.startScope(compId);

//get the original account values and set the acct balance

AcctData acct = acctDao.getAcct(trade.getAcctId());

double oldBalance = acct.getBalance();

if (trade.getSide().equals("BUY"))

{

acct.setBalance(acct.getBalance() - (trade.getShares() * trade.getPrice()));

}

else

{

acct.setBalance(acct.getBalance() + (trade.getShares() * trade.getPrice()));

}

//insert the trade and update the account

long tradeId = tradeDao.insertTrade(trade);

compController.registerAction(compId, "insertTrade", tradeId);

acctDao.updateAcct(acct);

compController.registerAction(compId, "updateAcct", oldBalance);

//close the compensation scope

compController.stopScope(compId);

}

catch (Exception e)

{

//reverse the individual database operations

compController.compensate(compId);

throw e;

}

}

}


Java iii

Transactions:

Questions?


  • Login