Giter VIP home page Giter VIP logo

gs-managing-transactions's Introduction

tags projects

This guide walks you through the process of wrapping database operations with non-intrusive transactions.

What you’ll build

You’ll build a simple JDBC application wherein you make database operations transactional without having to write specialized JDBC code.

Create a booking service

First, use the BookingService class to create a JDBC-based service that books people into the system by name.

src/main/java/hello/BookingService.java

link:complete/src/main/java/hello/BookingService.java[role=include]

The code has an autowired JdbcTemplate, a handy template class that does all the database interactions needed by the code below.

You also have a book method aimed at booking multiple people. It loops through the list of people, and for each person, inserts them into the BOOKINGS table using the JdbcTemplate. This method is tagged with @Transactional, meaning that any failure causes the entire operation to roll back to its previous state, and to re-throw the original exception. This means that none of the people will be added to BOOKINGS if one person fails to be added.

You also have a findAllBookings method to query the database. Each row fetched from the database is converted into a String and then assembled into a List.

Build an application

src/main/java/hello/Application.java

link:complete/src/main/java/hello/Application.java[role=include]

Your application has actually zero configuration. Spring Boot will detect spring-jdbc on the classpath and h2 and will create a DataSource and a JdbcTemplate for you automatically. Because such infrastructure is now available and you have no dedicated configuration, a DataSourceTransactionManager will also be created for you: this is the component that intercepts the @Transactional annotated method (e.g. the book on BookingService). The BookingService is detected via classpath scanning.

Another Spring Boot feature demonstrated in this guide is the ability to initialize the schema on startup:

src/main/resources/schema.sql

link:complete/src/main/resources/schema.sql[role=include]

There is also a CommandLineRunner that injects the BookingService and showcases various transactional use cases.

src/main/java/hello/AppRunner.java

link:complete/src/main/java/hello/AppRunner.java[role=include]

You should see the following output:

2016-09-01 09:47:55.031  INFO 16911 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executing SQL script from URL [file:/Users/foo/workspace/gs-managing-transactions/target/classes/schema.sql]
2016-09-01 09:47:55.052  INFO 16911 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executed SQL script from URL [file:/Users/foo/workspace/gs-managing-transactions/target/classes/schema.sql] in 21 ms.
2016-09-01 09:47:55.259  INFO 16911 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2016-09-01 09:47:55.282  INFO 16911 --- [           main] hello.BookingService                     : Booking Alice in a seat...
2016-09-01 09:47:55.292  INFO 16911 --- [           main] hello.BookingService                     : Booking Bob in a seat...
2016-09-01 09:47:55.292  INFO 16911 --- [           main] hello.BookingService                     : Booking Carol in a seat...
2016-09-01 09:47:55.306  INFO 16911 --- [           main] hello.AppRunner                          : Alice, Bob and Carol have been booked
2016-09-01 09:47:55.306  INFO 16911 --- [           main] hello.BookingService                     : Booking Chris in a seat...
2016-09-01 09:47:55.306  INFO 16911 --- [           main] hello.BookingService                     : Booking Samuel in a seat...
2016-09-01 09:47:55.312  INFO 16911 --- [           main] o.s.b.f.xml.XmlBeanDefinitionReader      : Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
2016-09-01 09:47:55.419  INFO 16911 --- [           main] o.s.jdbc.support.SQLErrorCodesFactory    : SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase, Hana]
2016-09-01 09:47:55.424  INFO 16911 --- [           main] hello.AppRunner                          : v--- The following exception is expect because 'Samuel' is too big for the DB ---v
2016-09-01 09:47:55.424 ERROR 16911 --- [           main] hello.AppRunner                          : PreparedStatementCallback; SQL [insert into BOOKINGS(FIRST_NAME) values (?)]; Value too long for column "FIRST_NAME VARCHAR(5) NOT NULL": "'Samuel' (6)"; SQL statement:
insert into BOOKINGS(FIRST_NAME) values (?) [22001-192]; nested exception is org.h2.jdbc.JdbcSQLException: Value too long for column "FIRST_NAME VARCHAR(5) NOT NULL": "'Samuel' (6)"; SQL statement:
insert into BOOKINGS(FIRST_NAME) values (?) [22001-192]
2016-09-01 09:47:55.424  INFO 16911 --- [           main] hello.AppRunner                          : So far, Alice is booked.
2016-09-01 09:47:55.424  INFO 16911 --- [           main] hello.AppRunner                          : So far, Bob is booked.
2016-09-01 09:47:55.424  INFO 16911 --- [           main] hello.AppRunner                          : So far, Carol is booked.
2016-09-01 09:47:55.424  INFO 16911 --- [           main] hello.AppRunner                          : You shouldn't see Chris or Samuel. Samuel violated DB constraints, and Chris was rolled back in the same TX
2016-09-01 09:47:55.425  INFO 16911 --- [           main] hello.BookingService                     : Booking Buddy in a seat...
2016-09-01 09:47:55.425  INFO 16911 --- [           main] hello.BookingService                     : Booking null in a seat...
2016-09-01 09:47:55.427  INFO 16911 --- [           main] hello.AppRunner                          : v--- The following exception is expect because null is not valid for the DB ---v
2016-09-01 09:47:55.427 ERROR 16911 --- [           main] hello.AppRunner                          : PreparedStatementCallback; SQL [insert into BOOKINGS(FIRST_NAME) values (?)]; NULL not allowed for column "FIRST_NAME"; SQL statement:
insert into BOOKINGS(FIRST_NAME) values (?) [23502-192]; nested exception is org.h2.jdbc.JdbcSQLException: NULL not allowed for column "FIRST_NAME"; SQL statement:
insert into BOOKINGS(FIRST_NAME) values (?) [23502-192]
2016-09-01 09:47:55.427  INFO 16911 --- [           main] hello.AppRunner                          : So far, Alice is booked.
2016-09-01 09:47:55.427  INFO 16911 --- [           main] hello.AppRunner                          : So far, Bob is booked.
2016-09-01 09:47:55.427  INFO 16911 --- [           main] hello.AppRunner                          : So far, Carol is booked.
2016-09-01 09:47:55.427  INFO 16911 --- [           main] hello.AppRunner                          : You shouldn't see Buddy or null. null violated DB constraints, and Buddy was rolled back in the same TX

The BOOKINGS table has two constraints on the first_name column:

  • Names cannot be longer than five characters.

  • Names cannot be null.

The first three names inserted are Alice, Bob, and Carol. The application asserts that three people were added to that table. If that had not worked, the application would have exited early.

Next, another booking is done for Chris and Samuel. Samuel’s name is deliberately too long, forcing an insert error. Transactional behavior stipulates that both Chris and Samuel; that is, this transaction, should be rolled back. Thus there should still be only three people in that table, which the assertion demonstrates.

Finally, Buddy and null are booked. As the output shows, null causes a rollback as well, leaving the same three people booked.

Summary

Congratulations! You’ve just used Spring to develop a simple JDBC application wrapped with non-intrusive transactions.

gs-managing-transactions's People

Contributors

gregturn avatar royclarkson avatar btalbott avatar cbeams avatar snicoll avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.