navigate site menu

Start learning with our library of video tutorials taught by experts. Get started

Java Database Integration with JDBC

Java Database Integration with JDBC

with David Gassner

 


Whether you're building a web- or desktop-based application with Java SE or Java EE, many Java applications need to integrate data from a relational database. This course describes how to read and manage data from relational databases such as MySQL and SQL Server using the Java Database Connectivity (JDBC) API.

Author David Gassner explains how to choose a JDBC driver and connect to one or more databases. He also provides detailed instructions on reading, selecting, and updating data; calling stored procedures; managing data via JavaBean classes or with prepared statements; and working with metadata.
Topics include:
  • Importing a MySQL database
  • Connecting to databases
  • Handling JDBC exceptions
  • Looping through result sets
  • Limiting the number of fetched rows
  • Filtering data with prepared statements
  • Calling stored procedures
  • Inserting, updating, and deleting rows with prepared statements
  • Using a persistent database connection
  • Committing and rolling back transactions

show more

author
David Gassner
subject
Developer, Databases, Programming Languages
software
Java
level
Intermediate
duration
2h 51m
released
Nov 28, 2012

Share this course

Ready to join? get started


Keep up with news, tips, and latest courses.

submit Course details submit clicked more info

Please wait...

Search the closed captioning text for this course by entering the keyword you’d like to search, or browse the closed captioning text by selecting the chapter name below and choosing the video title you’d like to review.



Introduction
Welcome
00:04My name is David Gassner, and I would like to welcome you to Java Database Integration with JDBC.
00:11JDBC is a set of Java interfaces and classes that will connect to your application to nearly
00:16any relational database management system.
00:19I'll show you how to write Java code to connect two different database management systems.
00:24Once Connected, I'll describe how to loop through rows of retrieve data and how to display their contents.
00:30I'll describe how to use preparedStatement object to create parameterized SQL statements,
00:36I'll then show you how to insert, update, and delete data and how to dynamically acquire
00:41information about your database structure.
00:44I hope that this course will help you get started with this important Java API and get
00:49ready to build data-aware Java-based applications.
00:54
Collapse this transcript
What you should know before starting this course
00:00This course is designed for software developers who already have some experience programming with Java.
00:06You don't need to have worked in any particular application environment, such as Java enterprise
00:11edition, web applications, or Android app development.
00:14You just need to understand the basics of Java syntax, how to create simple console
00:19applications, and how to use Eclipse to create, compile, run, and debug. If you're brand-new
00:25to Java, I recommend first watching my course Java Essential Training. You'll get an introduction
00:30to the Java programming language and some valuable information about how the language
00:34and virtual machine work during compilation and at runtime.
00:38You'll learn how to install Eclipse, how to create Java projects, packages, and classes,
00:43and you'll get an introduction to the fundamental concepts of object-oriented programming.
00:48You should then be ready for this course and for other lynda.com courses that put Java to specific use.
00:54When working with databases and JDBC, you'll need to use at least a little bit of SQL or Structured Query Language.
01:01In this course I'll show you all the SQL you need, including statements to select, insert, update, and delete data.
01:08But if you want to learn more about SQL, check out the lynda.com course, SQL Essential Training.
01:14So let's get started learning about working with Java and Databases with JDBC.
01:19
Collapse this transcript
Using the exercise files
00:00If you're a Premium Member of the lynda.com online training library, or you're watching
00:05this video series on a disc, you'll have access to the exercise files that accompany this course.
00:11I have copied the exercise files to my Desktop,
00:13but you can place them anywhere on your hard disk.
00:16The main exercise files for the course are divided into chapters, and within each chapter
00:22there are folders that are designed as projects that can be imported into Eclipse.
00:26They were created with Eclipse 4.2 or Juno but should be importable in older versions as well.
00:33You will need Java 7 installed to use any of these projects.
00:37To import any Project go in to Eclipse.
00:40From the menu, select File > Import, then from the Import dialog under General, select
00:47Existing Projects into Workspace > Browse and choose the Root folder for the project you want to Import.
00:53I'll start with my Desktop where I have installed the exercise files, then I'll go to
00:58Exercise Files/03_Connections for chapter 3, and I'll choose the project JDBCExceptions.
01:06I'll then follow the rest of the buttons to import the project into Eclipse.
01:11You should then be able to open the project in the Package Explorer view open the Source
01:15folder and its packages and open any of the classes.
01:18I have opened the Main class from this particular application with either the main class or
01:23the project selected, you should then be able to run the application by clicking the run
01:27button and the result will show up in the console view.
01:30If you have the editor maximized like this then the Console view will appear on the right.
01:35To get rid of it, click into the Console view and back on the editor.
01:39You can also debug by clicking an icon on the toolbar.
01:43And if there are any errors or breakpoints, you'll go into the debug perspective, and
01:47you might be prompted with a dialog before that happens.
01:51You can also run or debug using keyboard shortcuts. To find out about these keyboard shortcuts
01:56go to the Run menu. The keyboard shortcuts differ between operating systems, look here
02:01to find out the keyboard shortcut for your operating system.
02:05I have also provided some free exercise files that are available to everybody, regardless of membership status.
02:11These exercise files contain code, database scripts, and libraries.
02:17The code folder includes a single project that I'll describe later in the course.
02:21The database folder includes scripts for both MySQL and HSQLDB and one text file that contains
02:29to MySQL stored procedures that I'll use later in the course.
02:34The libs folder contains to open source Java libraries.
02:39These are drivers, one for HSQLDB, and one for MySQL.
02:44You can also download the latest version of these JAR files from the vendor sites.
02:49But to simplify things, I have included them in these Free exercise files.
02:53So that's a look at the exercise files that accompany the course.
02:56The Free exercise files are available to all, and the Main exercise files are available
03:00to Premium Members or those who have purchased the DVD.
03:04If you don't have access to these Main exercise files you can follow along with your own Java code.
03:09
Collapse this transcript
1. Installing Software
Testing your Java development environment
00:00The exercises in this course are designed to work with Java 7, the most recent version
00:05of the Java Programming Language as of the time of this recording.
00:09If you haven't programmed with Java 7 before, you want to install it on your computer and make sure it's working.
00:15If you need to install Java 7, you can get the JDK or the Java Developers Kit from Oracle.
00:21Go to the URL oracle.com/Java, that will take you to the main Java page,
00:27then go to the Downloads menu and select Java for Developers.
00:31On this screen you'll see that there are two downloads available, the JDK or Java Developers Kit,
00:36and the JRE or Java Runtime Environment. You'll want the JDK.
00:41I'll click that link, and I'll see a listing of all the different installations for various Operating Systems.
00:47You can choose from the Mac version or the Windows version, and notice that there are
00:52two versions for Windows, one for 64 bit and one for X86 or 32-bit.
00:58After following the rest of the instructions to install the JDK on your system, if you're
01:02working on a Mac, make sure that you have set the Java 7 Runtime as your default.
01:08To do this, go to the Java Preferences application, which you can find through Spotlight or from
01:14Finder by going to the Applications/Utilities folder.
01:18I'll open Java Preferences and show you the state it should be in.
01:22You should have Java 7 installed, and Java SE7 should be at the top of the list that makes it your default.
01:29If you're working on Windows, all you need to do is install the JDK.
01:34It'll be fine if it's installed side by side with Java 6 or an older version of the JDK.
01:39It just has to be present on your system.
01:42Once you have installed Java 7 on your system, the next step is to make sure that you can
01:46create and run a Java 7 project in Eclipse.
01:49I have already installed Eclipse, and I'll go to the Eclipse Preferences dialog.
01:54You can get the Preferences either through Eclipse Preferences on Mac or from the Window menu on Windows.
02:00In the Preferences dialog, go to the Java section and then to the Compiler and make sure your
02:05Compiler compliance level is set to 1.7, which is the actual underlying version number
02:10for what's called in marketing Java 7.
02:13If you don't see 1.7 as a possible option, make sure that you're running at least Juno Eclipse 4.2.
02:20If all that is set, now you're ready to create a simple project and make sure that some code will work.
02:26That would only work if you're running Java 7 or later.
02:29I'll close the Preferences dialog and create a new Java project.
02:33I'll name the project Java7Test, and I'll make sure that my execution environment JRE
02:39is set to JavaSE-1.7, and I'll click Finish.
02:44I'll open up the project and go to the source folder, and I'll create a New Class.
02:48I will name my class Main.
02:50I'll add it to a package called com.lynda.javatraining, and I'll make sure that I have checked the option
02:57to create a main method, and I'll click Finish.
03:00Now I'm going to execute a little bit of code that will only work correctly if I have Java 7 or later installed.
03:06I'll go to the class declaration and delete these comments, and within the class declaration
03:11but outside the main method I'll declare a static string field.
03:15I'll make it private and static, and I'll set its type as String, and I'll give it a value of one.
03:21I'll go to the main method, and I'll add a switch statement.
03:24I'll type the word Switch and press Ctrl+Space, and I'll use this switch code template.
03:29I'll set the key to value, and here's why: this is a Java 7 test.
03:33Java 7 adds the ability to use switch statements with string values, something you couldn't
03:39do with older versions of Java.
03:41So if this code works, then I know the Java 7 is working.
03:44I'll press Tab to go to my first case, and I look for a value of one as a string.
03:50I'll tab again, and I'll use the sysout code template, typing sysout, and then pressing Ctrl+Space,
03:55and I'll out put the string, the value is one.
03:59Now I'll go down to my default case, and I'll add another system output block, and I'll
04:04output the string, The value isn't one.
04:07I'll save my changes and run my application and in my Console, I'll see the string, the value is one.
04:13So if this code is working on your system then you know JDK 7 is working.
04:18Finally, I'm going to make a couple of other changes to my Eclipse environment and then
04:22I'll be ready to launch into the exercises in this course.
04:26I'm going to reset the current Java perspective.
04:29The Java perspective is installed as part of the Eclipse installation.
04:32I'll go to window and Reset Perspective and click Yes, and then I'm going to close the
04:37Task List view, which I won't need for this course.
04:41Then I'll save this reconfigure perspective as a custom perspective named Java DB.
04:46I'll go to the menu and choose Window > Save Prospective As, and I'll name this Java DB and click OK.
04:54Now at any time during the exercises, I'll be able to return to this custom perspective,
04:59and this will be my starting perspective in each of the exercises of this course. So Java 7 is tested.
05:05I know I'll be able to run Custom Java 7 code on this system, and I have customized my Eclipse
05:10installation, and I'm ready to get started with JDBC.
05:15
Collapse this transcript
Importing a MySQL database
00:00To follow along with the exercises in this course, you'll need a local installation of
00:05MySQL and a copy of phpMyAdmin, a web-based management system that lets you manage a MySQL Database.
00:12You can select from a number of approaches to installing this software on your computer.
00:16I describe how to install this software in the course installing Apache, MySQL, and PHP,
00:22which is a completely free course available in the lynda.com online training library.
00:28In this course, I will describe how to install separate components on either Mac or Windows,
00:32or you can select from one of the many available software bundles which include Apache, MySQL, PHP, and phpMyAdmin.
00:41These include WampServer for Windows, MAMP for Mac OS X, or XAMPP or BitNami, which are
00:47both available for both Windows and Mac.
00:50Throughout this course I'll be using MAMP, a software bundle specifically designed for use on Mac OS X.
00:57If you're using MAMP, there's one preferences thing you need to take care of.
01:01When you first install MAMP, you'll see that it's set ports of 8888 for Apache and 8889 for MySQL.
01:09It does this so you can run the copy of Apache included with the MAMP side by side with
01:14a copy of Apache included with the Mac.
01:17But for this course, you'll need to run Apache and MySQL on their standard default ports.
01:22To do this, go to this Preferences dialog to the Ports tab and click Set to default
01:27Apache and MySQL ports, and you'll see that the my SQL port is set to the standard port of 3306.
01:34That's what Java and JDBC will expect.
01:37I'll click OK, wait for the servers to restart, and then click Open start page, and here I'll
01:43see that MySQL is running on the correct port of 3306.
01:47If you're using any of the other configurations of Apache, MySQL, and PHP, this port should already be set for you.
01:55MAMP is the only software bundle that I'm aware of where you need to make this change.
01:59Now the next step, once you have confirmed that MySQL is running is to import a database that
02:04I'll be using throughout this course. I'll go to phpMyAdmin.
02:07If you're not sure where to find phpMyAdmin on your configuration, check the particular server bundle's documentation.
02:14Within phpMyAdmin, I'm going to create a database.
02:17I'll go to the Databases tab, I'll click into the text box, and I'll type the name of the
02:22database I want to create, explorecalifornia.
02:25If you're following along, make sure that you spell the name of the database exactly
02:29this way, all lowercase and all one word, because all of the exercises throughout the course will expect it.
02:36Click Create, and now your database has been created.
02:39Now, I'm going to import an SQL script that's provided as part of the Free exercise files that accompany this course.
02:46I have copied by Free exercise files to the desktop, but you can find them wherever you installed them.
02:52Within the Free exercise files there is a database folder, and within that folder there's
02:57an SQL file called exploreCalifornia.sql.
03:01This is a simple text file, and you can open it in any TextEditor.
03:05Within this SQL file there's a command to use explorecalifornia, the database that I have just created.
03:11And then the five tables that are a part of this database are dropped if they already exist.
03:17So if you want to refresh your database, you can just run this SQL script in the future,
03:22and it will delete all of the existing data and refresh the database table structure and content.
03:28Little further down in the script, for each table there's a create statement that describes
03:33the structure of the database and a series of Insert statements that populate a table with data.
03:38There are tables named Admin, explorers, packages, tours, and states.
03:44And the states table has 50 rows.
03:46I'll close my TextEditor, and I'll return to phpMyAdmin.
03:50Now I'm ready to import my database.
03:53I'll click into the database and click the Import tab.
03:56I'll browse to select my SQL file.
03:58I'll be sure to select the file with the file extension .sql.
04:03There are also files with extensions of .script and .properties, but those are for use with
04:08another Database Management System.
04:10I'll select the file and click Open, and then I'll scroll down to the bottom of the screen and click Go.
04:15If everything goes well, I'll see a message that the import has been successfully finished,
04:20and if I click into the database again I'll see my five tables have been created.
04:24For any of these tables, I can click into the name of the table.
04:27For example, I'll click into states, and I'll see the listing of all the data.
04:31Just see the structure of the database table, including the names of the columns which is
04:36important to know when programming with JDBC.
04:39I'll click this Structure tab, and I can also click any of the other tabs to run SQL statements,
04:45Search, Insert data, Export, Import, and Execute other operations.
04:50So if you successfully followed through the steps, you'll have a working MySQL Server
04:55installation, and you'll have imported the sample database that I'll be using throughout this course.
04:59
Collapse this transcript
Creating a database user in MySQL
00:00In order to make the coding of our exercise files consistent, I'm going to show you how
00:04to create a database user that has access to the MySQL database server, and we'll use
00:10the credentials for that user throughout the course.
00:13In phpMyAdmin go to the home-screen, from there click on the Users tab, depending on
00:20how you installed MySQL and what software bundle you used, you might see a variety of
00:26user identities in this list.
00:28Minimally, you should see one named root, which is the super user or administrator of the entire database server.
00:35It's typically a good idea to create your own database users.
00:39So on this screen I'll click Add user.
00:42I'll set my username and password to some very simple easy to remember values.
00:47I'll set the User name to dbuser, all lowercase.
00:52For the Host, I'll pull down the list and choose Local, and that sets the host to localhost.
00:59I'll click into the Password, and I'll type a simple string of dbpassword, again, all lowercase,
01:05and I'll type it twice to make sure I got it right.
01:09Now I'll scroll a little further down, and I'll click the Check All link, and that adds
01:14all privileges to this user.
01:16dbuser will be able to access all databases on the server and do anything that the database server allows.
01:23I'll go down to the bottom of the screen and click Add user, and I should see that my database user has been created.
01:30So that's the user identity that I'll use throughout all of these exercises.
01:35If you have any trouble connecting, you might try deleting the user and then re-creating
01:40it again and make sure that you type in the password carefully so that it's something you'll easily remember.
01:50
Collapse this transcript
2. Getting Started with JDBC
What is JDBC?
00:00In this video series, I describe how to integrate applications built with the Java programming
00:05language with relational databases using JDBC, and I'm going to start by describing the nature
00:11and history of JDBC and how it fits into the larger Java World.
00:15JDBC is an API, a set of interfaces and classes that let you easily connect to relational
00:22databases, such as Oracle, SQL Server, MySQL, and many others.
00:27It was originally known as Java Database Connectivity, but more recently it's been known by simply the acronym JDBC.
00:34JDBC was introduced into the Java programming language very early.
00:38It was included in JDK1.1 in 1997, and has been a part of all releases of Java Standard Edition ever since.
00:46The history of JDBC is a history of added features and improved performance.
00:52The original release in 1997 included the main classes and interfaces that you'll find
00:57yourself using all the time, including the Connection interface which lets you make your
01:01initial connection to a database, the Statement which encapsulate SQL code, and ResultSet
01:07which returns data from the server.
01:10Later versions of JDBC improved the features of the API, including the ability to update
01:15your data without SQL, improved performance, pooled connections, scrolling, and more data types.
01:22More recent releases have included more data types, the ability to work with stored procedures,
01:28and the ability to get metadata, or lists of tables and column information, from your database.
01:34In the most recent versions of Java, JDBC 4.0 was released with Java 6, and it included
01:40the ability to load drivers automatically.
01:43I'll describe the benefit of this feature in an early video of this series.
01:47And in the most recent version of JDBC, JDBC 4.1 which is included in Java 7, there are
01:53features that let you reduce the amount of code it takes to work with your databases. So who uses JDBC?
01:59It's most commonly used in web-based applications that are hosted in JEE or Java Enterprise Edition servers.
02:07These include J Boss, Tomcat, WebSphere, and others.
02:11Developers also commonly use JDBC when they're working on desktop applications or applets
02:16that are working either with local databases stored on the client computer or with remote
02:21databases accessed over the Internet.
02:24Less common uses include JDBC in Android applications.
02:28Android has its own API for working with local databases, specifically SQLite, and so
02:34developers typically don't use JDBC there.
02:37And when you're working with larger databases making calls from Android applications, it's
02:41more common to make calls to those databases through web services hosted by middleware servers.
02:47But if you're a Java programmer, it is important to understand what JDBC is and how it works,
02:53because even if you're working through Android or through web services, someone somewhere
02:57is probably using JDBC somewhere in your calling chain, and it's useful to know how it works.
03:03There are other ways of getting to databases without doing direct JDBC programming.
03:08There are higher-level abstractions that are delivered as part of the large application frameworks.
03:13For example, the Spring application framework includes something called JDBC Template.
03:18It simplifies the amount of code you have to write, but in the background it's using
03:23JDBC to talk to the database.
03:25There's a similar but perhaps less popular templating library called RIFE, which does basically the same thing.
03:32And then there are data mapping APIs, the most popular is Hibernate.
03:36Hibernate is something called an object-relational mapping API.
03:40It represents your database structure with Java classes and objects.
03:44In the background it's still using JDBC to communicate with the database, but it simplifies
03:49the amount of code you have to write in your own application.
03:53And there are other mapping libraries, such as iBATIS from Apache, and the Java Persistence
03:58API or JPA, which is actually a part of the Java EE platform.
04:03Again, regardless of whether you use JDBC directly, or you use one of these higher-level
04:08application frameworks or data mapping APIs in the background, JDBC is at work.
04:14So by working through this video series, you'll be able to gain a greater understanding of
04:19how the Java programming language connects to databases and what are some of the pitfalls and benefits of using JDBC.
04:25
Collapse this transcript
Choosing a JDBC driver
00:00Applications that use the JDBC API require drivers.
00:05A JDBC driver is a software library that encapsulates the logic you need to communicate between
00:11your application and a database management system or a database file stored on the local hard disk.
00:17All JDBC drivers follow the same set of rules that is the API, that's defined in Java Standard Edition.
00:24A driver library package will contain specific implementations of these Java interfaces.
00:30Connection, which lets you connect to the database, ResultSet, which encapsulates data returned
00:35from the database, Statement, PreparedStatement, and CallableStatement, which represent requests
00:41to the database, and many more.
00:44Not all JDBC drivers will support all features of the JDBC spec. Check the documentation
00:50for your particular database and your particular driver to see what it's able to do.
00:55But nearly all JDBC drivers will support these five interfaces.
00:59Typically, you'll get your driver packages from the database vendors themselves, a MySQL
01:05driver from MySQL an Oracle driver for Oracle, and so on,
01:08but there are also third-party drivers available both free and commercial.
01:12There are four distinct types of drivers, distinguished by their architecture.
01:17The oldest type of driver is called the Type 1 driver or the JDBC-ODBC Bridge.
01:23In the mid to late '90s when JDBC got started, ODBC or the Open Database Connectivity protocol
01:30was the dominant model for communicating with the database.
01:33And so Java first communicated with databases through ODBC.
01:37You would use the JDBC-ODBC Bridge driver, and then you would also use a separate ODBC
01:43driver that was designed for your specific database.
01:46At runtime, requests would go from the application through the JDBC API to the Bridge driver
01:52from there to the ODBC driver and then to the database.
01:56This wasn't particularly fast, but it was dependable, and one of the pros was that you
02:01could talk to any database for which an ODBC driver existed, and that meant pretty much every relational database.
02:08The downsides of the ODBC Bridge driver are that it's not 100% Java and therefore not
02:13portable between operating systems.
02:15Also you're working with two drivers not just one, and they both have to be on the same
02:19computer as the application, so you have increased maintenance.
02:23And finally, the ODBC driver has to match the database version, and so if you updated
02:28your database on the server, you'd have to go around to all the client applications and update those as well.
02:34The Type 2 driver combines a native API driver and a Java driver.
02:40They're both installed on the client system just like with the Bridge driver and the ODBC
02:44driver, but because you're working primarily with native APIs, the Type 2 driver tends to
02:49be very fast and can give you the best possible performance.
02:53Once again, just like the Bridge driver, you're not working in 100% Java, and therefore, your
02:58applications aren't portable between operating systems.
03:01The native API driver has to be installed on the application client and maintained,
03:06and once again, if the database is updated, the client software has to be updated as well,
03:10but if you want the best possible performance, a Type 2 driver might be the way to go.
03:15The Type 3 driver actually is installed in multiple locations. You'll have 100% Java
03:21driver that's installed in the client along with the application, but then with the Type 3
03:26driver architecture, you'll have a middleware server which hosts its own application, requests
03:32go at runtime from the application to the Type 3 driver that's installed on the client
03:36and from there over the network to the middleware server and from there to the database.
03:41With a Type 3 driver, the middleware driver can be native, and so the communication between
03:46the middleware and the database can be very fast, but once again, you have maintenance
03:51challenges because you have more than one driver to maintain.
03:54The fourth type of driver, and one of the most common, is called the Type 4, or the 100% Java thin driver.
04:02With a 100% Java driver, there is only one driver package, not two, and the driver is
04:07packaged with the Java application itself, whether on a client computer, or in a web environment
04:13on a Java Enterprise Edition application server.
04:16Requests go from your application to the driver that's on the client and then your communications
04:21go from the application through JDBC through the thin driver to the database server if
04:26it's out on the web, or to the database file if it's on the local hard disk.
04:31With the Java thin driver, you're communicating directly from the application to the database.
04:35There are no additional layers to install or maintain, and so maintenance is greatly simplified.
04:41The only downside is that you need a different driver package for each database you're working with.
04:47Most applications will only use a single database type, but if you're working with more than
04:50one database management system, you'll need to provide multiple drivers.
04:55In this course I'll be doing all of my demonstrations with the two Type 4 drivers.
05:00One will be for the MySQL database server, and with this driver I'll show you how to
05:05communicate with a database server that's accessed over the web.
05:08I'll be actually working with a local copy of MySQL and addressing it as local host,
05:14but the code I'll be using would work just as well if the MySQL server were hosted out in the Cloud.
05:20The other database I'll be working with in this course is called HyperSQL, or HSQLDB.
05:25HyperSQL is one of many pure Java databases that are used by Java developers, others include
05:32the Apache Derby database and H2. These databases run as in-memory databases.
05:38But the database is initialized with a local file, but then it runs in the same Java process as the application.
05:45So with these two drivers and these two database management systems, I'll be able to show you
05:49how to handle differences between databases while making your code as portable as possible,
05:55and I'll also be emphasizing the use of these Type 4 drivers, which are pure Java and can
06:00be encapsulated into your applications.
06:02There are other types of drivers out there that aren't directly recognized by the JDBC
06:07API but can also be useful.
06:09For example, in 2010 there was talk of a Type 5 driver.
06:14A Type 5 driver has the same architecture as Type 4 that is it's 100% Java and Thin,
06:20but it gives you better performance than a pure Type 4 driver.
06:23And then there are other drivers that don't have specific type numbers that can run in
06:27the same Java process as the application just like the HyperSQL driver I'll show you.
06:32But if you stick with learning the four main types of drivers that are defined by JDBC,
06:38Types 1, 2, 3, and 4, those will cover the vast majority of JDBC drivers that are available to Java developers.
06:46
Collapse this transcript
Connecting to a MySQL database server
00:00The first thing to learn in working with JDBC is how to connect to a database.
00:05I'm going to start with MySQL.
00:07To connect to MySQL, you'll need a Java driver, and you can get a free driver from mysql.com/downloads.
00:13On this screen, scroll down to the Connector section and look for Connector/J.
00:21You can get the most recent version of Connector/J from this website.
00:24But to make this very easy, I have included a copy of the driver in the free exercise files that accompany the course.
00:31Go to the Free exercise files, to the libs folder, and locate them mysql jar file and
00:36copy it to the clipboard.
00:38Now go to Eclipse and open this project, ConnectMySQL from the exercise files.
00:44If you don't have access to the exercise files, create a new Java project, add this class
00:49to the package com.lynda.javatraining.db and type in the code that you see here.
00:56That creates three constants named USERNAME, PASSWORD, and CONN_STRING.
01:00Now I'm going to add the MySQL driver to my project.
01:04I'll right-click on the project in the Package Explorer, and I'll create a new folder.
01:08You can name the Folder anything you like.
01:10I'm going to name it libs for libraries, then I'll Paste the jar file into the folder.
01:17Now, just because this jar file is a part of the project, doesn't make its code automatically
01:22available to the code in my application.
01:24I have to add the JAR file to the project's Build Path.
01:28To do that, I'll right-click on the JAR file, I'll choose Build Path > Add to Build Path.
01:33Later on I can configure the Build Path by right-clicking again, and once again going
01:38to Build Path, and this time selecting Configure Build Path, and that will take me to the Java
01:43Build Path Category of my Properties panel.
01:46I have added the JAR file to the Build Path, and I should now be able to call its code.
01:50To connect to MySQL database, you need these three string values, the USERNAME, the PASSWORD,
01:56and the CONN_STRING or URL.
01:59The USERNAME and PASSWORD are determined by the users in your database.
02:02I created the USERNAME, dbuser, and assigned it this password in a previous video of this
02:08series, and if you don't have that user set up, you should set it up now.
02:12So I'm going to uncomment those two lines of code, and they're ready to use.
02:16This last line of code creating the CONN_STRING has a format that's determined by the driver.
02:21The MySQL driver requires a CONN_STRING that starts with jdbc in lower case, then MySQL
02:28also in lowercase separated with colons.
02:30After MySQL, there's ://, then the DNS name or IP address of the host server.
02:38I'm working with MySQL on my local system, so the address of my server is localhost.
02:43But if I were working with a remote server, I might put in the IP address or that server's name.
02:48Finally, the last part of the string is the name of the database I'm connecting to.
02:53So again, if you don't have access to the exercise files that accompany the course,
02:57you can create this code easily.
02:59Now I'll move the cursor to within the main method.
03:01In Java 6 and Java 7 you can jump directly to connecting to the database.
03:06But in previous versions of Java, you first have to load the driver class into memory,
03:11and you do this with code that looks like this, Class.forName, and then you pass in the
03:16fully qualified name of your driver class as a string.
03:20The name of the MySQL driver is com.mysql.jdbc.Driver.
03:26If you type that code in, you'll see that a warning is displayed, and if you move the
03:30cursor over the Warning indicator you will see an Unhandled exception type of ClassNotFoundException.
03:37I'll click on the warning, and I'll add a throws declaration to the main method.
03:41So here's what this code is doing.
03:43Class.forName is used in Java to load a class dynamically.
03:47That is by loading its fully qualified name as a string.
03:51It loads the class into memory, but it doesn't create an instance of the class, that is it doesn't instantiate it.
03:57Now in Java 6 and Java 7, you don't need this code, and I'm working in Java 7, so I am going to comment it out.
04:04Now the next step is to create an instance of a class called Connection.
04:08I'll type in the name of the class, and it's actually an interface, and I'll press Ctrl+Space.
04:14For MySQL, you'll see that there are two interfaces available, one in the packagejava.sql and
04:20one in com.mysql.jdbc.
04:23You should always choose a version of an interface from java.sql.
04:27This will make your code more portable so you'll be able to take the same code that
04:30you wrote for MySQL and point it instead at another database like SQL Server.
04:35I'll select the Connection interface from java.sql, and that adds the import statement.
04:40Then I'll name the new object conn, and I'll assign it an initial value of null.
04:45The next step is to connect to the database.
04:48I'll type in conn =, and I'll call a method called DriverManager.getConnection.
04:53I'll type in the name of the class, DriverManager, and press Ctrl+Space, and that adds an import
04:58statement for that class.
05:00After I have added the import statement, I'll type in a dot and press Ctrl+Space, and I'll
05:04see that there are three versions of the getConnection method.
05:07I'm going to use the third version of the method that looks for a url, a user, and a password.
05:13For the url ,I'll choose CONN_STRING, I'll set the user to the USERNAME, and the password to the PASSWORD.
05:20I'll complete the code, and I'll expand my editors so we can see all of it, and that's
05:24all the code that I need to connect to my database.
05:27Now once again, I'm seeing the warning indicator, so I'll move the cursor over the warning indicator,
05:32and I'll see that I have an Unhandled exception type of SQLException.
05:36When you call to getConnection method if it succeeds everything will be fine, but if it
05:41fails in some way it will throw an exception, and you'll want to handle it explicitly.
05:46So I'll click on the warning indicator, and this time I'll surround the code with a try-catch block.
05:52Within the catch block which is catching SQLException, I'll delete the comment and the call to print
05:57stack trace, and then I'll add error output, I'll type in syserr, a code template and press
06:03Ctrl+Space, and I'll output the error to my error output.
06:07The final step is to close the connection.
06:10For all JDBC resources, including connections, statements, and results sets, if you open
06:17them you have to close them. There are a few different ways of doing this, but I'm going
06:21to show you the most explicit approach here.
06:23I let a finally clause after the catch, and within a finally clause I'll first find out
06:28whether the connection object is null.
06:30I'll use if conn not equal to null, and if that condition is true, I will call conn.close.
06:38Now once again, you will see that a warning is been generated I'll move the cursor over
06:42that warning, and I'll see that the call to the close method can also throw SQLException.
06:47Now you can write a whole bunch of complex code wrapping this if clause inside another
06:52try catch block, but a much simpler approach is to set your main method so that it throws SQLException.
06:59So I'll click on that warning indicator, and I'll Add the throws declaration, I'll go to
07:03the Throws Declaration, and because I commented out Class.forName, I no longer need to look
07:08for ClassNotFoundException, and that's my completed code.
07:12Now to verify that I have connected correctly I'll move my cursor within the try block, after
07:17the call to make the connection, and I'll use system output and an output Connected.
07:23Later on I'll show you how to get a lot more information from the database, including retrieving data,
07:27but for now this will be adequate.
07:30I'll save my changes, and I'll run my application, and I get the message connected.
07:35Now to verify that this code works the way I expect, I'll make an intentional error.
07:39I'll change my PASSWORD from dbpassword to dbpassword123.
07:44I'll save and run the code again, and this time I get an SQLException with a message of access denied.
07:50And so I know that my code is correctly structured, and I'm creating the connection if my credentials are correct.
07:56I'll change my code back so that it's correct, I'll test it again, and I'm connected and
08:01so now I know I'm ready to move on to the next step, which is retrieving data from my MySQL database.
08:06
Collapse this transcript
Connecting to a HyperSQL database file
00:00In order to provide a contrast between different database management systems, I'm going to be
00:05showing how to connect both to MySQL and to HyperSQL.
00:10HyperSQL is one of a number of 100% Java-based databases. Others include Apache Derby and H2.
00:16I have chosen a HyperSQL because its databases are defined in pure text files, which makes
00:22them very easy to use in a training environment.
00:25You can get the Drivers and all the documentation for HyperSQL from hsqldb.org. You'll see hyperSQL
00:32preferred to both by the name HyperSQL and HSQLDB. Just as with MySQL, you can download
00:39the Drivers for free, but I have provided the driver for HSQLdb as part of the free exercise
00:45files that accompany the course.
00:47I'll go to my libs folder, and I'll copy the file hsqlbd.jar to the clipboard, then I will return to Eclipse.
00:55I'm working with a copy of my first project, this one is called ConnectHSQLDB, and it's
01:00available in the exercise files, this starting version of the project is already set up for
01:05use with MySQL, and I'm going to make some changes so that it works with HSQLDB instead.
01:11I'll go to the libs folder and then I'll add the jar file and then just as I did with MySql,
01:17I'll add the Driver to the Build Path. Now I need a database.
01:22With MySQL the database was defined in the server environment, with HSQLDB you define
01:28a database in a text file, a script, and you accompany that script with a properties file.
01:34And these are both pure text files, so you can edit them with any text editor.
01:38I have provided a starting sample database as part of the free exercise files.
01:43I'll go to the exercise files root, I'll go to the database folder, and I'll select
01:47and copy these two files explorecalifornia .properties and explorecalifornia.script.
01:54Now I'll go back to Eclipse, and I'm going to create a new folder in the project, and
01:59I'll name that folder data, all lowercase. And then I'll paste my script files into place.
02:07I'm going to open the script file in a text editor, I'll right-click and select Open With >
02:13Text Editor, and then I'll expand the editor to full screen.
02:16This is a database script for HSQLDB, it has some configuration commands at the top, and
02:21then if you scroll down, you'll find commands that are defining the database.
02:26Here there is a command to create a user named SA when you create a brand-new database for
02:32HSQLDB SA, or System Administrator is the default root, or system administrator ID, and down
02:39here there is a command to grant the DBA permissions to the SA user.
02:44Here there is a set of commands that are defining the structures of the databases.
02:48Just as with my MySQL database, their tables are named Admin, Explorers, Packages, States, and Tours.
02:55They have the same basic column names, Datatypes and Configurations, including Auto Incrementing
03:02Primary Keys on four of the five tables.
03:05Scroll down further and you'll see the insert statements that are adding the data to the database.
03:10The other file that I pasted into place is called a properties file, I'll open that one
03:15also with a Text Editor, and I'll see that it just has some information about the nature
03:19of the database, which version of the HSQL database engine was used, when the database
03:24was created, the version number, and whether it's been modified.
03:29HSQLDB works at runtime by loading these files into memory when you first initialize the
03:34connection and then the database is maintained in memory.
03:38You can run HSQLDB in either embedded mode or in server mode. I'll be using it an embedded
03:44mode so that the HSQLDB engine is running in the same Java process as my application.
03:50So now I have my HSQLDB driver, and I have my database, and I'm ready to connect to it.
03:55I'll go to the Main.class, and I'm going to change a few things.
03:59First of all, notice that my USERNAME and PASSWORD are still set to dbuser and dbpassword.
04:05I'll go back to my explorecalifornia.script file, and I'll add that user so that I can
04:10make exactly the same kind of call I did with MySQL.
04:13I'll scroll up to the section where the users are being created, I'll copy and paste the
04:18create user command for SA, and I'll change the name of the new user from SA to dbuser.
04:24To make sure that the USERNAME and PASSWORD stay lowercase and match what I have in
04:29MySQL, I'll wrap them both in quotes.
04:31Now I'll add my new user to the DBA Permissions, I'll go down here and locate GRANT DBA to SA
04:38I once again copy and paste, I'll change the New Command so that I'm granting those permissions to dbuser, I'll save my changes
04:45to the script, and I'll go back to my Main.class.
04:48Now in my Main.class, I do have to make a change to my CONN_STRING or URL. Just as with MySQL,
04:55you start the CONN_STRING with jdbc, but then instead of mysql, you type in hsqldb.
05:02Instead of localhost, you will be loading this database from the local disk so type in data
05:08the name of the folder, which is a subfolder of the project, and then you refer to your
05:12database by the name of the database as the first part of the two filenames explorecalifornia.script and .properties.
05:20Don't include the file extensions ,only include the beginning part of the name.
05:25So now I have made my changes to the code, I'm using the same USERNAME and the same PASSWORD
05:30but a different connection string.
05:31I'll save my changes, and I'll run my application, and just as with MySQL, I see a message indicating
05:37that I have successfully connected.
05:39Now just like with MySQL, I'll make sure that I'm getting a message that's true.
05:43So I'll change my USERNAME to something that doesn't exist, and I'll try to connect again.
05:48And I get an exception named SQLInvalidAuthorizationSpecException, a different exception that I got with MySQL.
05:57And this is an indication that when you're working with different databases, what's happening
06:01in the background with Java might differ in some very interesting ways.
06:06But I know that I connected successfully, so I'll return my code back to that state
06:10with the correct USERNAME, the correct PASSWORD, and the correct CONN_STRING.
06:14I'll connect again, and now I know that that code is working, and I'm able to successfully
06:19connect the HyperSQL or HSQLDB.
06:24
Collapse this transcript
Executing a static SQL statement
00:00Once you have connected to a database, the next step is typically to send a request, and the
00:05most common sort of request is a simple SQL statement that retrieves data from the database.
00:11I'll show how to do this using the Statement interface and another interface named ResultSet,
00:16which encapsulates the data that's returned from the database.
00:19I'm working in a project called StaticSQL. This project's main class already has the
00:24code to connect to the database.
00:26It has the three strings, the User name, Password, and Connection string.
00:30And I'm working with an HSQLDB database.
00:33In addition to the connection, I also need an instance of Statement and an instance of ResultSet.
00:39When you call methods of these interfaces, just as with the methods of the
00:43Connection class, they might throw an SQL exception.
00:46So typically, you'll declare the objects outside of the try block and then execute their methods
00:52within the try block, and that will make them have the lifetime invisibility that you need.
00:57I'll move my cursor after the Connection declaration, and I'll declare a Statement.
01:01I'll type in the name of the interface and press Ctrl+Space, and I'll choose the version
01:05of statement from java.sql.
01:08Again, my goal is to make this code as portable between databases as possible.
01:12I'll name this object stmt and set it to null.
01:15Next, I'll declare my ResultSet, and again, this is the interface that will contain the
01:20data returned from the database.
01:22I'll name that RS, and again, I'll set it initially to null.
01:26Now I'm ready to create my statement.
01:28I will move the cursor after the code that's connecting to the database, and I will make a little bit of space.
01:34I'll instantiate the statement using this code, stmt, the name of the object, equals conn.create statement.
01:42Notice that there are a few different versions of the create statement method.
01:45A default Statement object is returned when you don't pass in any arguments.
01:50There's also a version of the method where you can set the type of the ResultSet and
01:54its concurrency, and that's the version that I'm going to use.
01:57The default ResultSet type will differ from one database to another.
02:01With MySQL, the default ResultSet object is scrollable. That means that you can move the
02:06cursor up and down, going to the first row, the last row, and moving around as you like.
02:12But with many databases, including HSQLDB, the default ResultSet type is forward only,
02:19meaning that the cursor will start before the data, and you'll be able to move forward
02:22to the end, but you won't be able to move back again.
02:25I'd like to set up my code to override that default and get a ResultSet that's scrollable.
02:31So I'm going to set the ResultSet type to a constant that looks like this.
02:35ResultSet, and I'll choose the constant TYPE_SCROLL_INSENSITIVE. That means that it's scrollable,
02:42but it won't be sensitive to any changes in the underlying data.
02:45Essentially, it's a read-only ResultSet.
02:48Now I also need to set something called resultSetConcurrency, and this will indicate whether I'm working
02:54with a read-only ResultSet or an updatable ResultSet, a ResultSet that has a live connection
02:59to the underlying database.
03:01For the best performance, if I'm only going to be reading the data, I'll set the ResultSet
03:06to read-only, and I'll do that with another constant of ResultSet called CONCUR_READ_ONLY.
03:12So now I have created my statement object, and I'm ready to send the request to the database.
03:17I'll instantiate my rs or ResultSet object, and I'll get data back by calling the Statement object, executeQuery method.
03:25When you call executeQuery, you can pass in any StaticSQL string.
03:30The nature of the SQL command is determined by the database you're working with.
03:34There's a common set of SQL commands that work across all databases, but there are many
03:39variations from one database to another.
03:41So again, for portability, I'm going to keep it simple.
03:44I'll call the executeQuery method, and I'll execute the SQL statement select asterisk from states.
03:51States is the name of a database table that exists both in the MySQL database and the
03:56HyperSQL database that I'm working with.
03:59Now, to test the results, I'm going to find out how many rows are returned.
04:03In JDBC, there isn't a single property of the ResultSet object that you can look at.
04:08So instead, you move the cursor to the last row of the ResultSet and then find out what
04:14row number you're on. I'll use this code rs.last.
04:18The last method means move the cursor to the end of the ResultSet, and then I'll do a little
04:23bit of system output, and I'll output a string of number of rows, and I'll append to that
04:29the result of the method getRow, which looks like this, rs.getRow.
04:34The getRow method returns an integer value, which represents the current row number.
04:39The JDBC ResultSet starts numbering its rows from one.
04:43So if I have a table of three rows, the getRow method would return one for the first row,
04:48two for the second, and three for the third.
04:50That's different than a Java array which starts counting at zero.
04:54And as long as you know the difference between the two, the numbering system for arrays versus
04:59the numbering system for databases, you'll be in good shape.
05:02I'll comment out the remaining System out Command, saying I'm connected, because now
05:07I'm interested in finding out how many rows of data I have.
05:10So that's it. I'll save my changes, and I'll run the code.
05:13And I get back the message number of rows 50, and that's correct. There are 50 states
05:19and 50 rows in the states table in my database.
05:22I'll clean up my code, I'll delete unneeded comments and close up some extra white space,
05:27and then I'll test it one last time, and I'll see that I'm successfully connecting,
05:32that I'm getting back a scrollable ResultSet where I can move the cursor up down and back and
05:36forth as much as I need to, and I'm able to get the data back that I need.
05:41Finally, I'll make sure that I have closed my resources.
05:44I'll return to my code, and I move down to my finally block where I am checking for the
05:49connection, making sure it's not null, and then closing it.
05:52Just like the Connection object, you need to explicitly close your Statement object and your ResultSet object.
05:58I'm going to copy this code and paste it in a couple of times.
06:02You should close objects in reverse order for how they were created.
06:07So the Connection was created first, then the Statement, and then the ResultSet, so
06:11I'm going to close them in reverse order.
06:13I'll change my first if clause to rs, and if it's not null I'll close it, then I'll
06:19change the second block to the Statement, changing both the conditional logic and the
06:23call to the close method.
06:25All three of these interfaces have this close method, and again, it's up to you as the developer
06:30to make sure that you're closing these resources when you're done.
06:33If you forget to close a resource, with a file-based database you'll probably be fine, but with
06:39a network environment you might end up leaving a connection open to your database server,
06:44and that can cause problems at the server level later on.
06:47Just make sure you have closed all of your resources when you're finished, and you'll be in great shape.
06:52Having made some more changes, I'll run the code one last time. I'm seeing I'm connecting
06:56and getting the data back, and so all this code is complete.
06:59And this can be used as a good model for how you execute any StaticSQL statement.
07:04
Collapse this transcript
3. Managing Database Resources
Connecting to multiple databases
00:00To make it easier to switch between databases. I'm going to re-factor the code that I have
00:05written so far, so I can easily switch from MySQL to HSQL by simply passing in a single argument to a method.
00:13My goal is to show that once you have a connection, the code you use to make a request to the
00:17database and process the results is almost exactly the same from one database platform to another.
00:24I'm working in a project called MultiConnect where I have versions of the Main class that
00:28I have already coded in other projects.
00:30I have one class that connects to MySQL, and I'll test that and make sure that it's working,
00:35and I have one that's connecting to HSQL, and I'll test that as well.
00:39Now, I have created a separate Utility class called DBUtil which only currently has some commented out code.
00:46I'm going to uncomment that code, and you'll see that there are four private strings,
00:51a username and a password, which will be usable on both databases because I have set it up so
00:56that the same user name, and the same password are available on both, and then two versions
01:01of my Connection string, one for HSQLDB and one for MySQL.
01:07This class will have static methods that either return objects or processed results, and it's
01:13first job will be to have a static method that returns a particular kind of connection
01:19whatever kind of connection I request.
01:21I will place the cursor after the static final string declarations, and I'll declare a new
01:27public static method that returns an instance of the Connection interface.
01:32As I have done in other classes, I'll be sure to include the import statement for the Connection
01:37interface from java.sql. I'll name the static method getConnection.
01:42Now, in order for my application to be able to request the type of database it wants to
01:47talk to, I'm going to create an enumeration,
01:50a set of possible values, and they will match the two types of databases.
01:54I will go to my package again, and I'll right-click and select New > Enum.
01:59I'll name my enumerator DBType.
02:03I'll create it, and then within the enum declaration, I'll type in constants representing each of the two databases,
02:11HSQLDB and MySQL, and that's all I need.
02:14The entire purpose of this enumerator is to guarantee that I'm requesting a database that I know exists.
02:20I'll save those changes and return to my Utility class.
02:24Now when getConnection is called, I require that the database type be passed in, so I'll add an argument.
02:31Its data type will be DBType, the name of the enum I just created, and its name will
02:36be dbType with a lowercase D-B.
02:39I'll expand the editor to full screen, and now within the call to the method, I'm going
02:44to inspect that arguments value and find out which type of database I'm supposed to connect to.
02:49I'll add a switch statement.
02:52I'll type in switch and press Ctrl+Space, and choose the switch case structure, and
02:56for the Key I will look at dbType, the argument that was passed in.
03:00The first case I'll inspect will be MySQL, the type from the enum class, and then before
03:07I fill in the code for this case I'm going to duplicate it.
03:10I'll select these three lines and do a duplication, and I'll change the case statement for the
03:15second case, for MySQL to HSQLDB.
03:19Now I'm ready to make and return my Connection object.
03:23For MySQL, I'll use a return statement, and I'll call a driver manager, making sure, again,
03:28to add the import statement, then I'll call the getConnection method. Once again, as I
03:33have previously, I'll use the three arguments version of the getConnection method, and for
03:38MySQL I'll pass in the Connection string M_CONN_STRING, and then the USERNAME and the PASSWORD.
03:45I'm not going to need my Break command here because I'm immediately returning the Connection object.
03:51Now I'll copy that code and paste it into the next case, I'll once again delete the
03:56break statement that I don't need, and I'll go to the second call and change the Connection
04:01string from M to H. And for the default, I'll return null.
04:06You'll see that there are warnings being displayed in Eclipse, I'll move the cursor, and I'll
04:10see that I have an unhandled exception of SQL exception.
04:14To keep this simple, I'm just going to add a throws declaration to my method signature.
04:19I'll click the warning and choose Add throws declaration.
04:22I save the change, and now my DBUtil class is complete.
04:26Its entire purpose is to receive a type and return a connection object.
04:31Now I'll put this utility class to use. I'll go back to the Package Explorer.
04:36And I'm going to use this class, ConnectHSQL.
04:39I'm going to duplicate this class, I'll copy and paste, and I'll name the new copy Main,
04:46and this will be my new Main class for my application.
04:49I'm going to close all the other tabs and expand the editor for this new class.
04:53Now for this version of the class I no longer need to store the Username, Password, and
04:58Connection string in the Main class, that's all being handled now by the database utility.
05:03So I'll delete those lines of code, then I'll go down to the try block where I'm getting
05:07the Connection, and I'm going to comment out that call.
05:11So I'm no longer getting the Connection directly from the driver manager, and I'll replace
05:15it with this code, conn = DBUtil, my new utility class, and I'll call getConnection, and I'll
05:23pass in the type of database I want from the enum class.
05:26I'll start with HSQLDB, and so now I'm making a connection to the HSQL database and getting data back.
05:33I'll save my changes, and I'll run the code, and I get back 50 rows from the states table
05:38that seems to be working.
05:40I'll clear the console, and I'll come back to my call to getConnection, and I'll replace it with MySQL.
05:45I have saved my changes and run the code again, and once again, I get back 50 rows because
05:51these two databases have exactly the same number of rows in the states table and,
05:56in fact, the exact same data.
05:57So now I have a re-factored application where I have moved all of the logic for how I get
06:02a connection to my database into Utility class, and I have also hidden the Username and Password
06:08and the Connection strings.
06:10Now as I start building out my application, I have a single place in my application to
06:14go to get a connection.
06:16And if I need to change the way I'm getting my credentials or how I'm connecting to the
06:20database, I have a single set of code to maintain.
06:25
Collapse this transcript
Handling JDBC exceptions
00:00Just as with all Java programming, when something goes wrong in JDBC, you'll get an exception.
00:06In JDBC, most methods of JDBC objects throw a class called SQLException.
00:13SQLException is extended from the Exception class, and it inherits all of the tools that
00:17are a part of that class, such as getMessage and getLocalizedMessage, string representations
00:23of an error message, getStackTrace, and many other tools.
00:27But JDBC is all about databases, and so its special exception class SQLException is specifically
00:34designed to give you information about what's going on in the database.
00:38SQLException adds these methods, getErrorCode returns an integer value which tells you what might have gone wrong.
00:45The Error code is unique to the particular database, so a numeric error code for MySQL
00:51won't be the same as for HSQLDB, and so on.
00:54And there's also a method called getSQLState which returns a five-character string.
00:59It's just like the error code.
01:01It's specific to the particular vendor and the particular database, but it's a string instead of an integer.
01:07To find out what these values mean, you'll need to look at the documentation for your
01:11particular database, MySQL, HyperSQL, SQL Server Oracle, and so on.
01:18I'm going to be showing you how to look at the Exception object and get these values
01:22out, but you'll need to look at the documentation to find out what they mean.
01:26There are also methods called getNextException, setNextException, and iterator.
01:31When something goes wrong at the database level, many times it'll be a cascading set
01:35of exceptions, and these methods let you deal with those stacks of Exception information.
01:41Let's take a look at some code.
01:42I'm working in a project called JDBCExceptions, which is just like the projects that I have
01:47created previously in this video series.
01:50It has the Utility class that lets me choose which database I want to work with, HSQLDB
01:55or MySQL, and then it executes a single statement and brings back a result.
02:01Before I run this code, I'm going to modify the SQL statement.
02:05So I'm more specific about the names of the columns that I'm getting from the database.
02:10I'll get rid of the asterisk and replace it with stateId and stateName, separated with a comma.
02:16These are the names of the actual columns in my states table in both databases.
02:21I'll test the code and make sure that I have got it correct.
02:24I'm working with HSQLDB first, and I get back to my data, and then I'll change from HSQL
02:30to MySQL, and I'll run the code again, and I see that it works there too.
02:35So now I'm ready to introduce an intentional error.
02:38I'll start by getting the structure of my database wrong. Instead of states, I'll look
02:43for data from a nonexistent table named state.
02:46I'll run the application, and I get back an error object.
02:50Notice that this error object is specific to MySQL.
02:53It has a pretty lengthy name, but it has the message Table 'explorecalifornia.state' doesn't exist.
02:59Now let's throw the same error for HSQL.
03:02I'll change my database type and run the code, and this time I get back a different error
03:07object, and it means the same thing, but the message is different, user lacks privilege or object not found.
03:14Now, to get more information out of this Exception object, I'm going to add some more detailed exception handling.
03:20I'll go to my Database Utility class, DBUtil, and I'm going to add a new method that I'll call processException.
03:27I'll use the keywords public, static, and void, I'll name the new method processException,
03:33and I'll have it receive a single argument data typed as SQLException, and I'll name the object simply e.
03:40For now my only goal is to output the detailed information about the exception.
03:45So I'm going to add three error output lines.
03:47I'll use the System.err code template, I'll expand it, and then I'll duplicate it a couple of times.
03:54For the first line I'll output the error message.
03:57I start with a label Error message, and then I'll call e.getMessage.
04:02Now this line of code would be the same regardless of what kind of Java exception I get.
04:07But now I'm going to process the methods that are unique to SQLException.
04:11I'll move the cursor to the second line, and this time the label will be Error code,
04:18and I'll append to that e.getErrorCode.
04:21And finally, I'll output the SQL state the string representation of the error.
04:28I'll save my changes to the DBUtil class, I'll go back to my Main class, and now within
04:34the catch block instead of outputting the error object in its raw form, I'll use my new
04:38utility method, DBUtil.processException, and I'll pass in the Exception object.
04:44I'll run the code now, and I see my error message, my code, and MySQL state.
04:50So my goal here is to start showing you some of the differences between databases.
04:54I'm currently working with HSQLDB, notice the Error code and the SQL state -5501 and SQL state of 42501.
05:04I'm going to spell my table correctly, but now I'm going to misspell a column name.
05:08I save the changes and run the code, and I get back exactly the same Error code and SQL
05:14state that I did before.
05:15So for HSQLDB, misidentifying a column or table returns the same exception.
05:22Now let's switch back to MySQL.
05:24I'll change my database type, I'll leave the code that's misidentifying the column name,
05:29I'll run the application, and this time I get back a different Error code and a different SQL state.
05:33That's expected because now I'm working with another database, and notice
05:37the SQL state is 42S22. Let's remember that.
05:42I'll go back to the code, I'll fix the column name so it's correct, and now I'll get the table name wrong.
05:48I'll run the code again, and I get a different Error code and a different SQL state, 42S02.
05:54Now let's explore some other errors.
05:57One of the most common errors is a user authentication error.
06:00I'll fix my column names and my table name.
06:03I'll go back to my DBUtil class where I'm storing my user credentials, and this time
06:07I'll get my username wrong.
06:09I'm working with MySQL, and I get an Error code of 1045 and an SQL state of 28,000.
06:15Now let's switch to HSQLDB, and I get back another Error code and SQL state, -4001 for
06:22the Error code and 28501 for the SQL state.
06:26What I'm trying to get across here is that the Error codes and SQL states are going to
06:30differ both from one database to another but also in their patterns within a database.
06:36One database like HSQL might use the same SQL state for two different but similar conditions,
06:43whereas another database might have distinct SQL states and distinct Error codes.
06:48The only way you'll know what these codes mean--as I have mentioned previously--is to look
06:53at the documentation for your particular database management system, but once you know what
06:58these error codes and SQL states mean, you'll be able to write more detailed and more useful
07:03exception handling logic in your own application.
07:08
Collapse this transcript
Closing database resources in Java 7
00:00As I have previously described in this video series, JDBC resources need to be closed when you're done with them.
00:06The Connection, the Statement, and the ResultSet are examples of these resources.
00:12In class of JDBC code, which I show in this project Java7Closeable, you declare your resources
00:18first and initially set them to null, then you actually instantiate them within a try
00:23block, as I have done here.
00:24And then you close them in a finally block first, making sure that they're not null so
00:29that you don't cause yet another error.
00:31Now all of this code can feel a little bit cumbersome, but in Java 6 and prior it's simply required.
00:37Java 7, however, gives us a new syntax called try-with-resources, which when you apply it
00:43to these JDBC resources, can clean up your code significantly.
00:47The try-with-resources syntax looks like this.
00:50You add code after the try keyword and before the code block, create a set of parentheses,
00:56and then you can instantiate your JDBC resources within those parentheses, and they'll be closed
01:02automatically for you when the try catch block is executed.
01:06You won't need the finally block at all.
01:08This works because the kinds of objects that you can place into the try-with-resources
01:12section include any object that implements interfaces called Closeable or AutoCloseable.
01:18Let's take a look at the documentation for the Connection interface as an example.
01:22I'll click on the word Connection, then I'll go to Dynamic Help, I'll go into the Java
01:27docs for the Connection interface, and I'll show that this connection extends an interface called AutoCloseable.
01:33The AutoCloseable interface, which has many sub interfaces and many implementing classes,
01:39has just a single required method called close, which returns void.
01:43So any object that implements this interface or implements closeable which has the same
01:48requirements can be added to a try-with-resources block, and if you take a look at the Java
01:53docs for the ResultSet, the Statement, and other similar JDBC classes and the interfaces,
01:59you'll find that they all have this close method, and that's because they all implement
02:03the interface AutoCloseable or Closeable. So, let's go back to the code.
02:07Here's how I'm going to clean this up. In Java 7, I'll expand my editor, and then I'm going
02:12to move these three lines of code that are declaring my objects into the try-with-resources section.
02:18I'll cut and paste them, and place them within the parentheses.
02:22Now I'm going to take the logic that's instantiating these objects and move it up as well.
02:27First, I'll do with the Connection. I'll grab the code that's calling the getConnection
02:31method, I'll cut it, and I'll replace the null value with that call, then I'll make
02:36the same sorts of changes for the statement.
02:38I will move the call to create statement to where the statement is being created, and
02:44I'll move the call to execute query to where the ResultSet is being created, then I'll
02:49delete these three lines of code which are no longer needed.
02:52Now, because these objects have been placed within the try-with-resources section, when
02:56the application is finished executing the try catch block, their close methods will be
03:01called automatically, and if they're null-- that is if they haven't been created for some
03:05reason--they won't throw errors.
03:07And that means that I don't need this finally block.
03:10I'll select that code, and I'll delete it.
03:12I'll select all of my code and go to the Source menu and choose Correct Indentation.
03:17Because I have made so many changes, I want to make sure that everything is formatted well.
03:21I'll save my changes, and I'll run the application, and I'll see that just as before I'm successfully
03:26connecting to the database, creating the statement and executing the query and getting back data from the database.
03:33So, if you're working with Java 7, you can significantly reduce the amount of code that's required
03:38to connect to your database and execute SQL statements.
03:42If you're working with Java 6 and previous versions, you'll still need to use the older
03:46syntax, declaring the objects first and setting them to null and then instantiating them
03:51in a try block and closing them in the finally block.
03:54And if you're working in Android, as of the date of this recording, Android still
03:58follows the rules for Java 6, and so you won't be able to use this try-with-resources syntax
04:03there either, but in Java 7 things have been improved significantly, and I encourage you
04:08to try it in your own code.
04:13
Collapse this transcript
4. Reading Data
Looping through result sets
00:00When data is returned from the database server, it's encapsulated within the ResultSet object.
00:06The ResultSet has a cursor and in-memory pointer that goes from row to row.
00:11When the ResultSet is first returned, the starting cursor position is before the first row of
00:17data, that is, it's not pointing to any data at first.
00:20You have to explicitly move the cursor to the data in order to read it.
00:24The cursor can either be before the first row of data, on a row of data, or after the last row of data.
00:30All ResultSets give you the ability to move the cursor forward, so the cursor starts before
00:35the first row, and the first thing you need to do is move it to the first row.
00:39If you're working with a scrollable ResultSet, you can explicitly move to a particular row,
00:44but if you're working with what's called a forward only ResultSet, that is a result set
00:48where the cursor can only move forward, then you move the cursor one row at a time by calling
00:53a method called Next. The Next method returns a Boolean value.
00:57When you call it, if it succeeds in moving the cursor to a row that has data, it returns
01:01true, and if it moves toward the row that doesn't have any data that would be after
01:05the last row, then it returns false.
01:08And so, when working with a forward only cursor, the most common approach is to use a while loop.
01:14Within the conditional block for the while loop, you call the Next method.
01:17And if it returns true, you know you're on a row that has data, and you process the data.
01:22And if it returns false, then you know you have gone passed the available data, and you can
01:27exit the while loop and continue executing your program.
01:30Within the while loop, while the cursor is on a row with data, you call various methods
01:35to retrieve the data.
01:36If a particular column has string values, you can call a method called getString.
01:41You can pass in either the name of the column as a string if you know it or the position of the
01:46column as an integer and the position start numbering at one.
01:50So let's take a look at some code. I'm working in a project called LoopingRows.
01:54In this project, Main method, I'm executing a query to retrieve all data from a table named Tours.
02:00Let's take a look at the structure of the Tours table.
02:03The Tours table has a number of columns.
02:04There is a primary key called tourId, a foreign key called packageId, a number of string columns,
02:11including tourName, blurb, description, and so on.
02:14A double-column called price, an integer column called length, and many others.
02:19I'm going to write some code that assumes that we're getting back a record set based
02:24on the structure of this table, and it's going to loop through the rows that are returned
02:28and output some content for each row. I will go to Eclipse.
02:32Now I'm not going to put all of this output code in the Main method. Instead, I'm going
02:36to create a Utility class that I can call from anywhere in my application.
02:40I'll go to my DBPackage, and I'm going to create a sub package.
02:44I'll right-click and choose New > Package, and I'll name my new package Tables.
02:49This new package eventually would contain one class for each table in my database.
02:55So I have created a new package, and now I'll create a new class for that table.
02:59I'll right-click and choose New > Class, and I'll name my class the same as the table, Tours.
03:05This is going to be Utility class.
03:07It won't be the start up class of my application, so I won't include a Main method, and I'll click Finish.
03:13Now I'm going to create static methods to process data. Within the class, I'll create
03:18a new public static void method, so I'll put in those keywords, and I'll call my method displayData.
03:25I'll set this method up to receive a single argument, data typed as a JDBC ResultSet.
03:30I'll type in ResultSet, press Ctrl+Space, and choose ResultSet from java.sql, I'll name
03:36this argument rs, and I'll create the code block.
03:39Now, for the purpose of this exercise, I'm going to assume that the cursor is starting before the first row.
03:45I could add some additional code to make sure of that, but for the way I'm going to use this
03:49code in this application, I'm going to know where the cursor is.
03:52So I'm going to start with a while loop.
03:54I'll type in while, and I'll choose a while loop with a condition.
03:58For the condition, I'll make it call to rs.next.
04:02So now as long as there's available data, I'll just keep on looping.
04:06I'm going to collect data from a number of columns and append it altogether to create a string for display.
04:12For this purpose I'll use a string buffer, I'll name this object simply buffer.
04:16And I'll instantiate it with the class's constructor.
04:21I'll expand my editor to full screen so I can see everything I'm typing.
04:25Now I'm going to get the current row number and append that as the tour number.
04:29I'll use buffer.append, and I'll first add in a label of the Tour space then I'll
04:35append to that the value of rs.getRow. Now this is not a static value.
04:41The number will be whatever is first in this record set, and so if you re-sort the data,
04:46in some way these values won't stick with the data.
04:50If you prefer, you could instead call getInt and pass in either the name or the column
04:55index of the column containing the primary key value.
04:58So for example, I could instead pass in getInt("tourId").
05:03So, after I have appended the primary key value, I'll then append a colon and a space.
05:08Now before we add more content, let's see how we're doing.
05:11I'll add some system output, and I'll output the value of buffer.toString.
05:15Notice that there are some warning icons when you call the next method or any of the
05:19methods that get data from the record set you might be throwing an SQLException.
05:24So I'm going to mark this method with the throws declaration, and indicate that it might throw that exception.
05:31I'll save my changes, and I'll go back to the main method.
05:34I'll place the cursor within the try block, and within the try block, I'll call this new
05:38static method that I have just created.
05:40I'll type in the name of my new class, and I press Ctrl+Space to make sure I have imported
05:44the class, and then I'll call the display data method and pass in the ResultSet.
05:49I'll save my changes and run the code, and I see that I'm correctly getting back 26 rows of data.
05:55So now I'm ready to fill in the rest of my display method.
05:58I'll go back to my Utility class, and I'll add some more code.
06:02After I have gotten the primary key, the next step will be to output the tour name.
06:06So I'll place the cursor after the call to the append method, and I'll append again.
06:10And this time I'll output the value of rs.getString, and I'll pass in the name of the column I'm
06:15interested in, tourName.
06:17Now the column names are not case-sensitive, and that's true for almost every database
06:22you might work with. It's certainly true with the MySQL and HSQLDB.
06:27So even though HSQLDB marks these column names as all uppercase and MySQL maintains the column
06:33names however you typed them in, you can type them however you like here in your Java code.
06:38Next, I'll get the price of the tour.
06:40I'll create a new double variable that I'll name Price, and I'll get its value from rs,
06:46and this time I'll call the method getDouble, and I'll pass in the name of the column price.
06:51Before I output it, I'd like to format it, so I'll use an instance of the NumberFormat
06:56class, I'll type in the name of the class, and import it from java.txt, and I'll name
07:01the object nf for NumberFormat, and I'll get its reference by calling the static method,
07:08NumberFormat.getCurrencyInstance.
07:09Notice that there are many methods that I could call from the NumberFormat class.
07:14This one's going to format the price as a dollar value.
07:17Then I'll format the price, I'll create a string called formattedPrice, and I'll get
07:21its value from calling the format method of the NumberFormat object with nf.format, and
07:27I'll pass in the price.
07:29And finally, I'll append that result to the buffer, using buffer.append, and I'll pass
07:34in a space and in an opening parenthesis, and then the formattedPrice, and then a closing parenthesis.
07:40I already have my code to output the buffer's value.
07:43So I'll save my changes, I'll go back to the main method, and I'll run the code again,
07:48and there is the result.
07:49I'm looping through the data that's returned from the database, and I'm outputting information
07:54from the rows one at a time.
07:56When I finished with the last row, the next time I call the next method, it returns false
08:01because there is no more data, and I exit the loop, and I'm done.
08:05So that's the most classic way of working with data returned from the database.
08:09The cursor starts before the first row, you call the Next method and each time it returns
08:14true you're on the next row of data.
08:16And you use the various get methods of the ResultSet to get a value from a column and process it in some way.
08:23
Collapse this transcript
Moving the cursor in scrollable result sets
00:00By default, result sets are forward only, that is, the cursor starts before the first
00:05row of data and can only move forward once.
00:08But a scrollable ResultSet gives you the ability to move back and forth in the result set as needed.
00:14You can make the ResultSet scrollable with most database management systems and different
00:18database management systems have different rules.
00:21For example, MySQL using the Connector/J returns a result set that scrollable by default.
00:27But HSQLDB can do a scrollable ResultSet, but you have to say you want it.
00:33You select the ability to scroll the data set when you create the Statement object.
00:37In this code I'm creating the Statement with the CreateStatement method, and I'm passing
00:42in a type of TYPE_SCROLL_INSENSITIVE.
00:45The ResultSet type can be scrollable or forward only, it can also be READ_ONLY or updatable,
00:51and it is possible to have a scrollable ResultSet that also updatable if you combine these properties in the right way.
00:57Once you have gotten a scrollable ResultSet into memory you can move the cursor that is
01:01the pointer to the current row using these methods, beforeFirst(), and first(), move
01:07to the position before the first row, and the first row itself, last(), and afterLast(),
01:12do the same thing, but for the end of the table and the absolute method receives an
01:16integer argument and moves to that particular row.
01:19As I previously mentioned, your number ResultSet rows starting with 1, not with 0.
01:24So if your ResultSet has say 50 rows, they are numbered from 1 to 50, not from 0 to 49.
01:30There are also methods that return boolean values that you can use to check the current cursor position.
01:36isBeforeFirst(), isFirst(), isLast(), and isAfterLast(), and the ResultSet object has
01:42other available methods to manage inserting new data and moving the cursor to particular rows after insertions.
01:49Take a look at the documentation for more details about that.
01:52But let's go to the code. I'm working in a project called scrollable.
01:55In this version of my application, I'm executing a query that's retrieving data from the state's table.
02:01Instead of using an asterisk for the columns, I'm explicitly naming the columns I want retrieved,
02:07which is typically a better practice than using the asterisk wildcard.
02:10I'll get back to result set with those two columns, and I have created a new class called
02:15states that in the db table's package, which has a displayData method,
02:20the displayData method is looping through the ResultSet, outputting first the stateId,
02:25the abbreviation, and then the stateName.
02:28I'll run the code in its existing state, and I get back the list of States.
02:32Now I'm going to demonstrate moving the cursor from row to row, notice that when I created
02:37my statement, I set the type as TYPE_SCROLL_INSENSITIVE.
02:41So I should get back a scrollable result set, regardless of whether I'm working with HSQLDB or MySQL.
02:48I'll place the cursor after the call to the displayData method, and first I'll move the
02:53cursor to the last row of the ResultSet, I'll call rs.Last,
02:57then I'll do some System.output, and I'll output (Number of rows), and I'll append to
03:02that the current row number using the ResultSet getRow method.
03:06I'll save and run that code, and at the end of the display, I see that the number of rows
03:11is 50, and that's correct.
03:12Now I'll add some code to move back to the first row,
03:16rs.First, and then once again I'll use some System.output, and I'll output the string,
03:22The first state is, and I'll append to that the value of the state name column using rs.getString,
03:29and I'll pass in the name of the column stateName.
03:32I'll save and run that code, and I see that the first state is Alaska, this table has
03:37the states in alphabetical order, now we'll add some code to move the cursor to the last row, rs.Last, and I'll make
03:44a copy of this output, and I'll paste it here, and I'll change from the first state to the
03:49last state, and I'll run that code, and I see that the last state alphabetically is Wyoming.
03:54Finally, I'll move the cursor to a specific row using rs.absolute, and I'll pass the value
04:00of 10, and once again I'll pasted my output code, and I'll change from first to 10th,
04:06and I'll run that code.
04:07And I'll see that I can successfully move the cursor as much as I need to.
04:11In this code, I'm scrolling first forward through all the data, then I'm moving to the end to
04:16get the number of rows, back to the beginning, back to the end again, and then to a specific
04:21row by its integer value.
04:23So that's a look at how you can use scrollable result sets.
04:26Now let's take a look at what happens if you don't specify that you want a scrollable ResultSet.
04:31I'm going to make a copy of this line of code that creates the Statement, and I am going
04:35to comment those new lines out, those are my backup, because I'm going to make some changes
04:39to the original code.
04:40Now I'll go to my CreateStatement method call, and I'll get rid of the options that I was passing in.
04:46Now, notice I'm working with HSQLDB, and I'll run the code, and this time I'm able to look
04:52forward through the data, but then I get an exception SQLFeaturedNonSupportedException,
04:58and that's because with HSQLDB the ResultSet by default isn't scrollable.
05:03It's a forward-only ResultSet.
05:05Now I'll change my databaseType from HSQLDB to MySQL, and I'll run the code again, and
05:12this time it works, and that's because with MySQL, you get a scrollable ResultSet automatically.
05:18To fix this and make sure that this code will work fine with either database, I'll always
05:23explicitly say that I want a scrollable ResultSet.
05:27So I'll go back to the code again, I'll delete these two lines, and I'll uncomment these,
05:32I'll save and run the code, and I see that it works fine with MySQL, and I'll switch
05:36back to HSQLDB, and I'll save and run again, and I'll see it works there as well.
05:41So for maximum portability, be explicit about the type of the ResultSet that you want, and
05:47you set those options when you create the Statement object.
05:52
Collapse this transcript
Limiting the number of fetched rows
00:00If you're working with a database where the tables have a lot of data, there will be many
00:04times when you need to retrieve only a certain amount of data from the table.
00:08You can limit the number of rows in a couple of different ways.
00:11One approach is to use a method of the statement interface called setMaxRows.
00:16There are some complications in trying to use this, especially with Java 7, where you're
00:20using to try-with-resources block to instantiate your objects.
00:24I'm working in a project called LimitingRows, and I'm starting off with the ResultSet that
00:30contains all of the data from the Tours table.
00:32I retrieve the data, and then use this method of the Tours class which I have created in a previous video.
00:39The displayData method receives the ResultSet object as an argument, loops through its data,
00:44and displays its data in the console.
00:46I'll run the code and show that I'm retrieving all of the data from the Tours table.
00:51I'll also switch from MySQL where I started to HSQLDB,
00:55and then I'll run the code again and show that it works there as well.
00:58Now, I'm going to limit the number of rows that I'm retrieving.
01:02If you want to do this using pure JDBC and not SQL, you do it with a setMaxRows method.
01:07This is a method of the Statement object, and you might be tempted to try this, stmt.setMaxRows,
01:14and I'll pass in a value of five.
01:16Meaning I only want to work with five rows, but when I save that change, I'll see all kinds of errors appear.
01:21The problem is that you can't modify an object within a try-with-resources block.
01:27This is a Java 7-specific issue.
01:29If you're working with Java 6 or prior versions, you would have declared your Statement object
01:34outside the try block, then instantiated within it, and then it would have worked fine.
01:39But if you're working with Java 7, and you want to take advantage of try-with-resources, this is the complication.
01:45You can only setMaxRows within the try block, not in the try-with-resources section.
01:50So I'll move that code down a few rows.
01:52I did that on Mac by holding the Option key down and pressing the Down Arrow, and if you're
01:57on Windows, you can do the same thing with Alt and the Down Arrow.
02:01Now I'll save my changes again, but now I'm calling executeQuery before I call the setMaxRows method.
02:07And when I run the code, I still get back all of the data.
02:11So I'll make another adjustment.
02:13I'll take the code that's creating the ResultSet, and move that down so it's below setMaxRows.
02:19But now I also have to close the ResultSet, so I'll add a finally block, and I'll call
02:25rs.close, and to make that possible, I'll need to declare the ResultSet outside the try block
02:32so that it's visible in the finally block.
02:34I'll move the cursor above the try, I'll declare the object, and then I'll remove the data
02:41type from the line of code that's instantiating the object.
02:44I'll test my code, and now it runs correctly.
02:47I'll switch back to my other database, MySQL, and test it there as well.
02:51And I'll see that it works there as well.
02:53So if you want to use the setMaxRows method, you can.
02:57But using it in combination with Java 7's try-with-resources syntax is complicated.
03:03There is one other issue though with setMaxRows.
03:05Let's say you're dealing with a database table that has 500 rows, and you say you only want 5.
03:11When you execute the SQL statement, you'll actually be retrieving all 500 rows from the
03:17database into your Java client, and then when you say setMaxRows with the statement, you're
03:22saying discard the unused rows.
03:25You're not saving any memory or any network bandwidth if you're dealing with the database server.
03:30So I'm going to get rid of all the code that I just generated.
03:34So instead of using setMaxRows, I'm going to use pure SQL to limit the number of rows that I want to retrieve.
03:41I'm going to put all my code back the way it was and just comment out the stuff that I'm not using.
03:46I'll comment out my declaration outside the try block, I'll take my two lines of code
03:50that are executing the query, and I'll move them back to within try-with-resources.
03:55I'll add the data type back to the executeQuery method, and I'll comment out setMaxRows.
04:00Now here's how you can limit your data using Pure SQL.
04:03I will use something called the LIMIT clause.
04:07The LIMIT clause can be placed in a couple of different places in your select statement,
04:11depending on what database you're using.
04:13But if you want to use the LIMIT clause in a way that's broadly compatible across many
04:17database platforms, place it after the FROM clause.
04:21I'll place the cursor inside the SQL string before the closing quote, and I'll add a space
04:27then I'll append to that another bit of code LIMIT 5.
04:31You can use the LIMIT clause with either one or two numbers.
04:34If you only put a single number in, you're saying this is how many of rows I want, and
04:39I want the first set of rows that are available from the database.
04:43So here I'll get the first five rows.
04:46I'll clean up my warning at the end because I'm now declaring the ResultSet within the try-with-resources.
04:51I don't need this finally code anymore so I'll delete it.
04:55And now I'll run the code, and I once again get back five rows of data.
04:59Now let's say that instead of the first five rows you wanted five rows from an arbitrary
05:04segment of the ResultSet.
05:06You can do this, too, by adding another numeric value to the LIMIT clause.
05:11You separate the two numbers with a comma. I'll start by using 0, 5.
05:16That means starting with row zero, the first row of the ResultSet give me five rows.
05:22I'll save the change and run the code, and it looks exactly the same as it did before
05:26when I was using setMaxRows, but now I'm only retrieving those rows from the database.
05:32And particularly when working with a network database server this is clearly a better approach
05:37because I'm not chewing up network bandwidth, and I'm not using memory in my client that
05:42I just don't need to use.
05:43I'll once again switch databases, and I'll test it in HSQLDB, and I'll see that it works exactly the same there.
05:50One last note about the LIMIT clause, the first value is the starting row.
05:55You might remember I said that with ResultSet columns you start numbering at one, so if
06:00you want to refer to the first column of the ResultSet, it's column one and not column zero.
06:05But in SQL, when you're using the Select statement with the LIMIT clause, you always start numbering
06:11at zero for the number of rows, so you start numbering at one for columns in a Java ResultSet
06:17and zero for rows in SQL. And just keep those two things straight, and you'll be in great shape.
06:23Now I'll test this a little bit further.
06:25I'll change the numeric value representing the first row I want to retrieve from zero to five,
06:31and now I get back rows six through ten.
06:34And if you want to develop a paging interface, that is a client that pages through data
06:39one set of rows at a time, this is clearly the best way to do it.
06:43By putting your request directly into your SQL statement, you limit the amount of memory
06:48you're using in your client, you limit the amount of network bandwidth you're using,
06:52and in general you limit the amount of data that you're retrieving from the database.
06:57
Collapse this transcript
Filtering data with prepared statements
00:00So far in this video series, I have shown you how to work with static SQL statements, statements
00:05that are the same when programmed, and when executed at runtime.
00:09But in many applications, you'll need to use parameterized SQL statements, statements where
00:15there are placeholders that you fill in with variable values at runtime.
00:18In JDBC, you do this with a class called PreparedStatement.
00:23The PreparedStatement class lets you set up an SQL statement as a string with these placeholders
00:28and then fill them in with variable values.
00:30I'll demonstrate this in the project Prepared Statements.
00:33In this version of my console application, I have a static string representing the SQL statement.
00:39Right now, I'm retrieving all of the data from the Tours table.
00:42And then, when I display the data using this version of the displayData method, I'm first
00:48moving the ResultSet cursor to the end of the ResultSet, then getting the row to find
00:52out how many rows I got back.
00:54And then, if I got back zero, I say there were no tours found.
00:57And if I got back more than zero, I output the number and loop through and display the actual data.
01:03I'll test this version of the application before I make any changes.
01:07And I see that I'm displaying all of the data from the database.
01:10Now let's change the requirements of our application.
01:12Let's say that the user is allowed to enter a numeric value representing the largest amount
01:17of money that they want to spend on a tour, and we want to retrieve only those tours where
01:22the price is less than or equal to the value that the user provides.
01:26The first step, I'll use a class named inputHelper that I have added to this project.
01:31In this version, in addition to the getInput method which returns a string, I have a method called getDoubleInput.
01:37It calls the getInput method and then parses it and turns it into a double value.
01:43And if it fails because the end user enters a value that can't be parsed as a double,
01:47it throws an instance of number format exception.
01:50So going back to my main class, I'll place the cursor inside the main method right at
01:55the top, and I'll declare a new variable called maxPrice.
01:59Then I'll set up a try catch block.
02:01In the try block, I'll set the value of maxPrice using the inputHelper's static method getDoubleInput,
02:08and I'll display a prompt of enter a maximum price.
02:11Within the catch section, if an error is thrown, I'll use a little bit of Error output, and
02:17I'll output a static string of Error: invalid number, and then I'll just clean up this
02:22try catch block so that instead of looking for the Exception object, I'll look for an
02:26instance of NumberFormatException.
02:29So now I have a value that I can plug into my SQL statement.
02:33I need to prepare the SQL statement to accept this variable value.
02:37I'll go up to the string where I'm setting the SQL statement, and I'll add a WHERE clause,
02:42and I'll use this syntax, WHERE price <= ? and then I'll put in a question mark.
02:49Each time you add in a question mark, that's a placeholder for a variable value.
02:53In order to process this SQL statement, I need to add another class.
02:58Instead of statement, I'm going to use something called a PreparedStatement.
03:03The PreparedStatement is the JDBC class that knows how to process SQL statements with variable parameters.
03:10I'll place the cursor down within this try catch block, and I'll add Prepared to the
03:14beginning of the class name.
03:16Then to make sure that I have imported PreparedStatement, I'll move my cursor to the end of the name
03:21and press Ctrl+Space, and I'll choose the version of PreparedStatement that's a member
03:26of the java.sql package.
03:28That adds an import statement at the top of the code.
03:31I'll open up my imports, and show that that was added correctly.
03:34Then I'll collapse them again.
03:36In order to instantiate a PreparedStatement object, instead of calling create statement,
03:41you call a method of the connection object, called prepareStatement.
03:45So, I'm going to change that code here. I'll call the prepareStatement method,
03:49and then in order to use this properly, before I pass in the type and the read-only setting,
03:55I'll pass in the SQL string as the first argument.
03:59Then just as with a static statement, I'm setting the type so I can scroll, and I'm
04:04setting it to read-only. So now I have my PreparedStatement object.
04:08Before I execute the query, I have to fill in the placeholders or parameters.
04:13To do that, you call one of the many methods of the Statement object.
04:17For example, I'm filling in a double value, a numeric value that could have fractions.
04:22So, I'm going to set the value this way, stmt.set, and notice how many different Set methods there are.
04:30Each of these methods takes an integer value and then the value you want to set.
04:35The parameters are indexed starting at one, not zero.
04:38I only have one parameter in MySQL statement, the price.
04:42So I'll choose the right method for my data type which is Double. I'll call setDouble.
04:47I'll pass in a value of 1, meaning I'm setting the first parameter, and then I'll pass in
04:53the maxPrice value as the value that I want to set.
04:57Notice that I'm getting a warning.
04:58I'll move the cursor over to the warning indicator, and it tells me that The local variable maxPrice
05:03may not have been initialized.
05:05To fix that, I'll place the cursor within my catch block.
05:08And after I output the message that the user entered an invalid string that couldn't be
05:12parsed with a number, I'll return, and that will fix the flow of this code, so that now
05:18by the time I get to the code that's setting the double value, I'll know that the maxPrice is valid.
05:24Finally, I have one more change to make.
05:26When you use a PreparedStatement, you have already passed in the SQL string when you prepared the statement.
05:31So, you don't pass it in again when you execute it.
05:35So I'm going to remove SQL as an argument of the executeQuery method.
05:40When I call executeQuery now, I'm working with the statement that already has the SQL,
05:45and that has already set its parameters. I'll save and run the code.
05:49When prompted, I'll click into the console, and I'll enter a value of 500.
05:54That means I want to see tours that cost less than or equal to $500.
05:59I get back 11 tours. I'll run the code again. This time, I'll pass in a value of $300.
06:06And I get fewer tours than I did the last time. I'll run it again.
06:10This time I'll pass in $100. And I get back just one tour. And I'll run it one last time.
06:16And this time, I'll look for a really cheap tour, one that only costs $50.
06:21And I get back the message, no tours were found.
06:23You can set up your PreparedStatements with as many placeholders as you like and as many
06:28data types as you need to.
06:30Remember that there are many versions of the set method, one for each data type,
06:34so if you're working with an integer value in the database, use the setInt method, if
06:38you're working with a string, use setString, and so on and so forth.
06:43The PreparedStatement interface is available for pretty much every database that has a JDBC driver.
06:49It lets you use parameterized SQL statements and greatly simplifies the process of creating
06:54applications that work with a database dynamically.
06:59
Collapse this transcript
Calling stored procedures
00:00In previous videos of this series I have described how to work with static SQL statements using
00:05the Statement interface and with parameterized statements using PreparedStatement.
00:10There is a third interface that's available in JDBC called CallableStatement which can
00:16be used with stored procedures and functions that are defined at the database level.
00:20Let's begin by talking about the nature of a stored procedure.
00:24In this project, StoredProcs, I have a main class that's using PreparedStatement and a
00:29parameterized SQL statement as a String, and I'm filling in the parameter at runtime.
00:34I am going to take this parameterized SQL and move it to the database level as a stored
00:40procedure and then show you how to call that stored procedure from your JDBC application.
00:45I'll start by minimizing Eclipse and my browser, and I'll get to this file MySQL StoredProcs.txt.
00:52The syntax for defining stored procedures can vary widely from one database to another,
00:58so I'm going to focus on just one database for this exercise, MySQL, and I have provided
01:03all the code you need for MySQL in this file, which is available in the free exercise files
01:09that accompany the course. You can find it in the database folder as MySQL StoredProcs.txt.
01:15I have the code here for a number of different stored procedures. I'm going to use this one
01:20called GetToursByPrice. Just as in the previous exercise, this SQL has a parameterized value,
01:27what MySQL calls an in parameter, a value that's passed in at runtime.
01:31I am going to select all the code starting with the DROP command and going all the way through DELIMITER.
01:37Now, if you're curious about what those Delimiter commands are doing, the default end of line
01:42delimiter for MySQL is a Semicolon, but SQL uses that Semicolon as well.
01:47So in this code, I temporarily set the DELIMITER for MySQL to a double slash, and then
01:54the semicolon will be taken as the DELIMITER only for the SQL statement.
01:58The double slash is used here to say I'm finished creating the procedure, and then I
02:02reset MySQL DELIMITER back to a semicolon.
02:06So I'm going to select all of this code starting with the DROP command and going all the way
02:10through the call to the DELIMITER command, and I'll copy that to the clipboard.
02:14Next, I'll go to my browser where I have already opened phpMyAdmin, and I'll go to my explorecalifornia
02:21database and then click on SQL, and this is where I can execute arbitrary SQL statements,
02:27I'll paste in that code.
02:28I'll scroll up to make sure I have got all of it starting with the DROP command.
02:32This makes sure that if I already have a stored procedure of this name that I'll drop it first
02:36before I re-create it and then I'll click Go.
02:39I confirmed that want to drop any procedure that might already exist with this name and click OK.
02:45And I get back messages indicating that the code was executed but no data was returned,
02:50and that's what I expect.
02:52Now I'm going to test the procedure for MySQL, I'll delete all that SQL, and in order to call
02:57the stored procedure directly in phpMyAdmin, I'll start with the word call, then the name
03:02of my stored procedure, then a parameter that matches the required data type, I will pass
03:07in 300, and I close the statement with a semicolon, I'll click Go, and I get back
03:12a total of seven rows just what would I expected.
03:16I'll go back to MySQL statement, and I'll try it again.
03:18I will once again call GetToursByPrice, and this time I'll pass in 100, and I'll click Go, and
03:26once again as expected, I get back a single row.
03:29So now I know that my stored procedure is working as expected, and I can go and try
03:34to call it from Java.
03:35I'll close the Browser, and I'll close the Text Editor, and I'll return to Eclipse.
03:40Because MySQL logic is now part of my stored procedure I don't need it in the application itself.
03:46So I'm going to delete this SQL code and replace it with the same call I used in phpMyAdmin
03:52but I'm going to wrap the call inside a pair of braces.
03:55So I'll start with an opening brace, then once again call, then the name of the stored
04:00procedure GetToursByPrice, and then a place holder, which is exactly the same as in a
04:05standard SQL statement a question mark, I don't need all that with my codes, so I'll
04:10close it up a little bit, and now that SQL code is ready to use.
04:14Now I'll move down to where I have declared my prepared statement object.
04:18When you're recalling a stored procedure or function from the database instead of using
04:22the prepared statement interface, use the CallableStatement.
04:26I'll start with word the Callable, I'll press Ctrl+Space, and I'll choose the CallableStatement
04:31interface from java.sql, and instead of calling the method to PreparedStatement, I'll call the method PrepareCall.
04:39Just as with PrepareStatement when you call the PrepareCall method, you can pass in the
04:44SQL String and the type and whether you want your result set to be read-only or updatable.
04:50Everything else is exactly the same just like with PreparedStatement the CallableStatement
04:54has set methods for various data types.
04:57I'm still passing in a double value so I'll call setDouble, and I'll pass in maxPrice
05:02as the first value. And I am ready to test my code.
05:05I run the application, I'll type in a value of 300, and I get back my expected number of rows.
05:11I'll run the application again, I'll type in a value of 100, and I'll get back one row,
05:17and I'll run it one more time, and this time I'll type in 50 and I get back no rows.
05:21So all I have done here is to move MySQL logic from my client application into the database itself.
05:29You can do this with any database management system that supports stored procedures and
05:34functions, take a look at the documentation for your database management system to learn
05:39how to define the stored procedures and functions, but when you're in JDBC the syntax for calling
05:44the stored procedures and functions is always pretty much the same.
05:49
Collapse this transcript
Handling multiple values from stored procedures
00:00Many Database Management Systems let you create stored procedures that return more than one
00:05value, for example, in MySQL.
00:08You can create a stored procedure that returns both a result set and one or more of what are called Out Parameters.
00:15Here's the syntax in MySQL, I have provided this code in the file MySQLStoredProcs.txt,
00:21which is part of the free exercise files that accompany this course.
00:25As with any stored procedure in MySQL, you start by setting the DELIMITER to a double
00:29slash or some other String that won't be in conflict with SQL.
00:33When you create the procedure, you define arguments. Here I am declaring an IN parameter, the same
00:39parameters as I used in a previous exercise, but I'm also defining an OUT parameter, a
00:44value that can be passed back from the stored procedure.
00:47In this stored procedure, I'm executing two separate select statements, the first one
00:52selects the count of rows from the tours table.
00:56It selects the count, but then instead of naming that return value as a part
01:01of the result set as you might do in conventional SQL,
01:04I'm taking the value of count, and I am passing it to the OUT parameter by its name, total.
01:10Then I'm executing a second SELECT statement. This one will return a conventional result
01:15set, I am returning all columns, but I could just as easily put it on this column names
01:20that I want to return.
01:22It's essential that the select statement that returning the result set be executed last.
01:27That's how you'll get that data out of the StoredProcedure.
01:30The SELECT statements that are simply setting the value of OUT parameters such as my first
01:35select statement can be placed anywhere in the chain.
01:38So I'm going to take this code and import it into my MySQL database.
01:42I'll select everything starting with a DROP command and ending with the DELIMITETR command,
01:47and I'll copy it to the clipboard.
01:49Then I'll go to phpMyAdmin, I'll go to my database, and to the SQL panel I'll paste in that code and click Go.
01:56I'll confirm and I'll check and make sure that everything was executed correctly.
02:00Now I'm ready to run this code for my Java application.
02:04I'll switch back to Eclipse where I am working with a project named StoredProcOut, this version
02:09of my project is using the CallableStatement interface already.
02:13And right now it's calling the stored procedure GetToursByPrize, which receives a single argument.
02:19In this version of my application I'll change MySQL String from the original stored procedure
02:24GetToursByPrice to the new stored procedure GetToursWithCountByPrice.
02:30And I'll match the arguments in the original stored procedure in MySQL. I had two arguments,
02:35so I'll set two arguments here.
02:37I'm still calling a stored procedure, so I'll use the CallableStatement just like I did before.
02:42But now I have a couple more bits of code to add to deal with that OUT parameter.
02:47I'll place the cursor after the code that's setting the IN parameter, which is the double value of the Max price,
02:53then I'll add another line here, and I'll call another method called registerOutParameter.
02:58Just as with the set methods, you can identify your parameter either by its ordinal position,
03:04that is 1, 2 and so on in the SQL String, or by its name.
03:09I'm going to use a version of registerOutParameter where I pass in the name of the parameter
03:13as a String, but again I could also pass the value of 2.
03:17Next, I indicate the data type of the value. I'm expecting that you set the data Type
03:22by using a constant that's the part of a class called Types, and I'm going to set this to Types.INTEGER.
03:28So I have set the IN value with setDouble, and I have registered the OUT value with registerOutParameter.
03:35Now I execute the query. After I execute the query, the results will be returned automatically.
03:41It always returns the result set resulting from the last SQL statement in the stored procedure.
03:46But to get the OUT parameter, I have to do a little bit more work.
03:50I'll declare an integer variable that I'll name nRows, and I'll get its value by calling
03:54a method of this statement object not of the result set. It will look like this stmt.getint
04:01you'll find that there are other methods called getdouble, getstring, and so on.
04:05And as before, I can reference the parameter either by its position in the argument list
04:10or by its name. I'll choose the version where I reference by Name, and I'll type in the
04:14name of the parameter, and now I have that value returned as the variable nRows.
04:19The code in my displayData method in the Tours class already has code to figure out how many
04:25rows there are, but I'm not going to need that anymore. That value is already being
04:29returned by the stored procedure.
04:31So I'll go into the displayData method and comment out those two lines of code, and I'll
04:36re-factor this so that nRows is passed in as an argument.
04:41I'll save those changes, I'll go back to my main class, and I'll change the way that I'm
04:46calling displayData, and I'll pass in nRows.
04:49So I have moved some of the actual work from the client application back to the database.
04:54In fact, I no longer even need a scrollable result set because now I'm not moving the
05:00cursor forward and back, I'm only moving it forward looping through the returned rows.
05:05I'll test my application, I enter a value of 300, and there is a result the Number of tours
05:11is correct, and there is the data.
05:13And I'll run it once again, and this time I'll pass in a value that gets back no rows,
05:17and there's the result.
05:18From the user's point of view it's all working exactly like it did before, but now I have moved
05:23as much of the logic as I can back to the database.
05:26This lightens the load on the client, reduces the amount of work you have to do and the
05:31amount of memory you have to use, and eliminates the need for a scrollable result sets, which
05:36do take a little bit more memory and resources than forward only result sets.
05:40You can do it either way moving the logic into your client or defining it and keeping it on the database.
05:46As a JDBC developer, the more you know about what your database management system can do,
05:51the more choices you'll have.
05:54
Collapse this transcript
Using generic getter methods in Java SE 7
00:00So far in this chapter, I have been describing how to retrieve data from ResultSet using
00:05specifically-typed Getter methods.
00:07For example, in this version of my project, GenericGetters, in my Tours class, I have
00:12calls to the methods getInt, getString, and getDouble, and I'm selecting the method to
00:18match the data type of the column.
00:20So, the tour ID is an integer, so I call getInt, tour name is a string column, so I'll call getString, and so on.
00:27In Java 7, there is a new approach, a Generic Getter method called getObject that you can
00:33use on every column of ResultSet, and you explicitly data type the return value using a different syntax.
00:40Now again, this new Generic Getter method is only available in Java 7.
00:45So if you're using an older version of Java, you should stick with these explicitly data typed method calls.
00:50But if you are working with Java 7 and therefore JDBC 4.1, this new approach is just another
00:57option, another tool in your toolkit.
00:59I'll start this exercise by re-factoring this code a bit.
01:02I'm going to take the expression that's retrieving the tourId, and I'll extract it to a local
01:07variable of the method.
01:09I'll select the expression, then I'll right-click, scroll down and choose Refactor, and then Extract Local Variable.
01:16I'll name my new variable the same as the column name, tourId.
01:20So that creates a local variable here, and then I'm using that value on the next line
01:25to build my string buffer.
01:27I'll do the same sort of re-factoring for the tourName.
01:30This is all just to make the code a little bit more readable.
01:33I'll select the expression, right-click, choose Refactor > Extract Local Variable, and again,
01:38I'll name the new variable to match the column name, tour name.
01:42I'll group these two variable declarations together, and then I'll take another that
01:46already exists, the declaration of the price variable, and I'll move that up.
01:50So now I have one section of code where I'm getting all the values I need from the current row.
01:56I'm going to reformat the code a little bit, and make it even easier to read, and now I'm
02:01ready to use the new Generic Getter method.
02:03I'm going to keep a copy of this code around so I can compare the two styles of coding to each other.
02:09I'll select and copy and then paste in, and then I'll comment out the second version,
02:14and I'll make the changes to the first version. Here's how you use the Generic Getter.
02:18I'll start with the integer.
02:20Instead of calling getInt and passing in either the name of the column or the ordinal position
02:25of the column as an integer, you call getObject.
02:27So, I'll get rid of that, and instead of getInt, I'll call getObject.
02:32You'll see that there are a few versions of this method, but I'm using this version, the
02:36one that accepts a column label as the first argument and then a class.
02:41The class will determine the data type that will be returned from the method.
02:45You'll see that we're using the diamond operator, and the T in the middle means type.
02:50What is the data type that we're looking for?
02:53So I'll call getObject, and just as before, I'll pass in the name of the column that I'm
02:57retrieving from, and then, I'll pass in a class and its class field, and it looks like
03:04this for an integer, Integer.class.
03:07That means that I want to retrieve the tourId column, and I want to data type it as a class.
03:13Now, you might think that I would have to explicitly cast the value as I'm passing it back.
03:18For example, adding casting syntax at the beginning.
03:21But because of the way the getObject method is written, when I say that I'm passing in
03:25an integer class here, that's the class that's going to be returned, and so it will automatically
03:30be returned as my primitive integer, and I don't need this casting syntax.
03:35Now, let's do the same thing with the string.
03:37I'll get rid of the call to the getString method, and instead I'll call getObject,
03:42once again, I'll call the version that accepts the name of the column and the type.
03:45I'll pass in the name of the column as tour name, and the type will be string.class.
03:50Finally, I'll do the same thing with the price. I'm retrieving a double value.
03:56So I'll call the getObject method, and I'll pass in the name of the column, price, and
04:00the data type which I'm going to set initially as Double.class.
04:03So, take a look at these two versions of the code.
04:07In the first one, you're calling the same method over and over again, getObject, and
04:11you're setting the data type using that second argument.
04:14In the second version, which is the older version, you're setting the data type with the actual method names.
04:19I'll run this application, and I'll see that it works exactly the same as it has in previous
04:24versions of the project.
04:26If you see a pop-up dialog asking you whether you want to run an application or an applet, choose Java application.
04:32But here's a little problem with this version of the code.
04:35I'll go back to my Main class and show that I have started off working against MySQL, and
04:40this code works with MySQL.
04:42But now I'm going to switch to HSQLDB or HyperSQL, and I'll run the code again.
04:48And this time I get an error.
04:50Depending on the state of your installation of Eclipse, you might not see this dialog.
04:54Instead, you might go right to the debug perspective.
04:58I'll see that I'm getting a ClassCastException which was not caught by MySQL Exception catch clause.
05:04I need to add a little bit more try catch code to see what's happening.
05:08So, I'll terminate the project and go back to my code, and I'm going to add in another catch section.
05:13And this time, instead of SQLException, I'll catch the global exception object, Exception.
05:19And here, I'll just do a little bit of system error output, and I'll pass in the Error object.
05:24I'll run the code again, and this time I can see the explicit error, BigDecimal cannot be cast to double.
05:31So what's going on here?
05:32When you call the getObject method with a double column or a float, the specification
05:37for JDBC says that a BigDecimal will be returned, not a double or a float.
05:43Now, if you have watched my Java Essential Training course, you might remember that I described
05:48why the Big Decimal class exists.
05:50The double and float objects can't be guaranteed to be absolutely precise because of the nature
05:56of how floating-point arithmetic happens on the computer, you'll frequently have additional
06:01decimal values that you don't want.
06:03Whereas the BigDecimal object can always return a very specific value.
06:08With some database drivers, the BigDecimal can be converted to the Double, and that was the case with MySQL.
06:14But with other database drivers, such as HyperSQLs, you have to always use the BigDecimal.
06:20So, for portability between databases, if you're working with columns that are doubles,
06:25floats, currency, or anything else that might have fractional values, I recommend always returning a BigDecimal.
06:32So I'm going to change the data type of the value that I'm returning into, the price,
06:37and I'll change it to BigDecimal.
06:39I'll make sure to choose it so that I get an import statement for the class.
06:42Then I'll go to my getObject call, and I'll change that from Double.class to BigDecimal.class.
06:49I'll save and run the code again.
06:51And with HyperSQL, it now works, where it broke before.
06:54I'll go back to my Main class and change back to MySQL, and I'll run the code again.
07:00And I'll see that it works there as well.
07:02If you use the BigDecimal to contain your doubles and floats, you'll pretty much guarantee
07:07that things work fine across different databases.
07:10But if you try to stuff things into a double or a float value using this new Generic Getter
07:14method, it will work on some databases but not on others.
07:18So that's a look at how you can use the new Generic Getter method.
07:21In the rest of the code throughout this course, I'm going to continue to use the older style
07:26because it is compatible with older versions of Java.
07:29But if you're working with Java 7, you might want to upgrade to this new version of the code.
07:34
Collapse this transcript
5. Managing Data
Managing data entities with JavaBean classes
00:00My focus so far has been on weeding and displaying existing data from our backend databases.
00:05Now, I'm going to move to how to manage your data, how to insert new rows, and how to update
00:11and delete existing rows.
00:12I'm working in a version of my project called JavaBeans, and I have made some changes to the
00:17classes and how they're implemented.
00:19In this version of the project, in the Tables package there are now three classes named
00:24AdminManager, StatesManager, and ToursManager.
00:27These classes are the manager classes for each of the named tables, Admin, States, and Tours.
00:33Each of them now implements a method called Display All Rows.
00:36I'll show you how this is implemented in each of the classes.
00:39The Display All Rows method now contains all of the code needed to retrieve the data and
00:44display it in the console.
00:45There is an SQL variable that's local to the method, then within the try-with-resources
00:50block, a Connection, a Statement, and ResultSet are being created.
00:54Then there's some looping code to output the data from that table.
00:57You'll see the same sort of implementation is available in the AdminManager, the StatesManager,
01:03and the ToursManager.
01:04In order to manage data, you need a good way to encapsulate rows.
01:09Each row is a data entity, and in Java, we represent data entities with a type of class called a JavaBean.
01:16The syntax of a JavaBean is fairly straightforward.
01:19A JavaBean class has a name, it has private properties to represent its values, and then
01:25public Setter and Getter methods that allow the rest of the application to access and modify those values.
01:31I'll show you first how to create a JavaBean class and then how to use it in a couple of different ways.
01:36I'll go back to the Package Explorer, and I'm going to create a new package.
01:41I'll right-click on the DB package and choose New > Package,
01:45and my new package will have an extension of .beans.
01:49In a complete application, I would have one JavaBean class for each database table.
01:54For now, I'm just going to create one JavaBean class for the Admin table.
01:58I'll right-click on the new package and choose New > Class, and I'll name my class exactly
02:04the same as the table, but if the table uses a plural value such as tours or packages,
02:10the bean will have a name that's singular, because it's going to represent a single row
02:14of the database table, not all of them.
02:17For the Admin table, I'll just use the word Admin.
02:20I'll make sure I'm not creating a main method.
02:22This class is designed to be instantiated to represent a single row of data and not
02:27to launch a full application.
02:29Once the class has been generated, I'll create one private field for each column in the table.
02:34In my Admin table, the first column is an integer column, and it is named adminId.
02:39Next, I'll create a string, and I'll name it username.
02:44And finally, I'll create another string, and I'll name it password.
02:47I'm setting the names of my fields exactly the same as my database column names, but
02:52you don't necessarily have to do that.
02:54Especially in an environment where your database tables might have very long names, you can
02:59use shorter field names to make your Java programming a little bit easier.
03:03Now, I'm going to generate public methods called Setters and Getters.
03:07I'll go to the menu and choose Source, then Generate Getters and Setters.
03:11I'll click Select All to indicate that I want methods for all three private fields.
03:16I'll set the insertion point for this new code to after the Last member, whatever it might be.
03:21I'll leave the Access modifier set to public, and I'll click OK.
03:25And that creates all the methods I need for my JavaBean.
03:28I'll clean up my code a little bit, adding a little bit of extra white space and deleting
03:32it where it's not needed. And this JavaBean class is now ready to use.
03:36One more word about JavaBeans, if you look at the specification for JavaBeans, you'll
03:40find that a true JavaBean is supposed to be serializable.
03:44You do this by adding the implements keyword and then Serializable.
03:48Make sure to include the import statement for the Serializable interface.
03:52The serializable interface doesn't have any methods you have to implement.
03:56It's a marker interface.
03:57It's just a way of saying to the rest of your environment that this class can be serialized.
04:02That is saved to a local persistent environment such as a database or to a local disk.
04:07When you mark this as Serializable, you'll see a warning.
04:10I'll move my cursor over the warning indicator, and I'll see that it's asking me to create
04:14something called a serialVersionUID field.
04:18I'll go ahead and create this by clicking on the warning indicator, and adding a generated serial version ID.
04:24This is a long value, and it's used to uniquely identify the class when it's been serialized.
04:29Now, the truth is you don't need this code for the kind of application we're building here,
04:34And even though the JavaBean spec says that all JavaBeans should do this, if you don't
04:39need the functionality for your particular application, you don't need to add it in.
04:42So I'm going to delete that, and I'm also going to take away the implements marker and
04:47remove the import statement.
04:49So, now I have a JavaBean that can represent a single row of my Admin table, and I'll be
04:54able to use this JavaBean class to represent data that I want to update and delete in my application.
04:59
Collapse this transcript
Retrieving a single row as a JavaBean object
00:00In a previous video I described how to create a JavaBean class to represent the structure of the database table.
00:06The Admin class has one private field for each column of the Admin table and the datatypes
00:12of the class matched the datatypes of the columns.
00:15There are private fields and public getters and setters.
00:18The names match the JavaBean convention where the getters start with the word get and the
00:23setters with the words set and then the rest of the names of the methods match the fields.
00:27The fields can match the database column names, and they do here, but they don't have to.
00:32Now I'm going to show how to use this JavaBean class to represent a single row of data retrieved from a table.
00:38I am working in a version of my project called RetrieveBean, and in this version of the project
00:44my AdminManager class has a new method called getRow.
00:48The getRow method receives a single argument datatype as an integer.
00:52I have named it to match the database column name Admin ID, and that's the primary key
00:56column of the database table.
00:59Then there is an SQL variable, a string that has the statement I'm going to execute with
01:04a question mark for the placeholder. That value will be provided by the end user.
01:08Then I'm creating a result set, a connection, and a prepared statement.
01:12I'm taking the value passed in, in the argument and setting it for the placeholder and then
01:17executing the query. But for the moment I'm just returning null.
01:21Now, I'm going to replace the return statement with the logic that takes the data received
01:26from the query and wraps it in an instance of my JavaBean.
01:30I will move the cursor after the call to execute query, and I'll add logic to test whether I got back data.
01:36If the query returns one row of data, I will be able to move the cursor from its initial
01:41position before the first row to the first row by calling the result sets next method.
01:47So I will use an if statement, if rs.next. If this returns true, it means I got data back.
01:54But if it returns false, that means that the user provided a value that doesn't match anything
01:59in the database table.
02:00I'll move my return statement to within the else clause, and I'll also output an error,
02:05No rows were found, now I will add logic to wrap up the data that was found inside the if statement.
02:12So if the next method returns true, then I have data to work with.
02:16I will create an instance of my Admin class.
02:19Remember that it's in the beans package, and you do need an import for it.
02:23I will name this new object bean, and I will instantiate it with the classes No arguments constructor method.
02:29Now I will set its fields using its setter methods.
02:34First, I will set the primary key bean.setAdminId, and I will just use the value that was passed in as the argument.
02:41Next, I will set the two string fields, username and password, and I'll use the values from the result set.
02:46I will call bean.set username, and I will pass in rs.getString, and I will identify
02:53the column I want by its name, userName. Then I'll set the password field.
03:02Once again, I'm using the setString method.
03:06For a database table that has more columns, simply call as many versions of the set method
03:10as you need to and use the appropriate methods of the result set to get the datatypes that you need.
03:16Get string for strings, get double and get int for integers and doubles, and so on.
03:21Now my bean object is complete.
03:23I have instantiated it, and I have set its values, and I will return it to the calling context.
03:29And that's the complete method. I will review all of the code.
03:33The primary key value is passed in as an argument, the SQL statement has a placeholder for that
03:38primary key value, I am using a prepared statement object so I can pass the value
03:42in using one of the setter methods, and I am executing the query.
03:46If I get data back, I wrap that data in an instance of my JavaBean class and return
03:50it, if I don't get data back, I return null.
03:53Now, let's go to the main class and call this method.
03:56I will place the cursor after the call to the AdminManger's displayAllRows method, and
04:01I will add code that lets the user indicate what row they want to work with.
04:05I will declare a new variable called AdminId, and I will get its value from a new method
04:09of the InputHelper class called getInteger input.
04:13I will set a prompt of Select a row.
04:17Now I will use that value to get a JavaBean object representing the matching data.
04:22I will declare a new JavaBean object, and I will use the Admin data type, and I will
04:27set the name of the object as bean, and I will instantiate it using AdminManager.getRow,
04:33and I will pass in the AdminId.
04:35Now I will test whether I got data back from the query.
04:37I will use an if else clause.
04:39I will set my condition to if, bean has a value of null.
04:44So if the bean is null, that means I didn't get any data back.
04:48In my output manager's method, I am already outputting an error message.
04:52I am going to move that to the main class.
04:54I will cut it from here and paste it into my main class in my if clause.
05:00But then in the else clause, if I did get data back, I will display that data's information.
05:05I will use a series of system outputs.
05:08The first one will have a label of AdminId and a call to the getAdminId method of the JavaBean object.
05:14I will duplicate that line of code a couple of times and then I will change the labels
05:19and the methods that I'm calling.
05:21For the second one, I will use UserName as the label, and I will call getUserName.
05:25And for the third one, I will set the label to Password, and I'll call getPassword.
05:30So now I am ready to test my application.
05:32I'll make sure that I saved all my classes, then I will go back to my main class and run
05:36the application, I'll type in a value of 2, which won't match row, and I'll get back the
05:42error message, No rows were found.
05:44But then I'll run the code again, and I'll pass in the correct value of one, and I get back the data.
05:50So now I have an object that I can pass around the application.
05:53I can get the data object from one method and pass it into another and in the next set
05:58of videos I'll show you how to use this object to manage updates and deletes of existing data.
06:03
Collapse this transcript
Inserting rows with prepared statements
00:00Once you have created a JavaBean class to represent the structure of a table, you can start adding
00:05code to your application to insert update and delete rows.
00:09I'll start with inserting data.
00:11In this version of the project InsertSQL, my AdminManager class has a new method called Insert.
00:17It accepts an instance of my JavaBean class as an argument, and it already has an SQL command.
00:22An SQL command to insert data looks like this.
00:25It starts with the INSERT command, then into, and the name of the table.
00:29In this admin and then a common delimited list of the column names you are inserting into inside parentheses.
00:36You follow that with the keyword values and then the values you are inserting also comma
00:40delimited and also in parentheses.
00:43For JDBC, I'm representing those values with the question mark placeholder, and this
00:48method already has the code to create the connection object and a prepared statement.
00:53I'm going to add the code to populate the placeholders with values.
00:56I will move the cursor into the code block after the opening brace and make a little
01:00bit of extra space, and I'll call this set string method of the statement object twice
01:06once for each placeholder.
01:07I'll start with stmt.setString, and I will pass in a parameter index of one for the first
01:13parameter, and I will pass in the bean objects getUserName method.
01:18Then I will do the same thing for the password.
01:20I will once again call setString, I will pass in 2 this time, and now I will call the bean
01:25objects get password method.
01:27Once you have populated the SQL statement, you can execute the update, and I'll call stmt.executeUpdate
01:33to pass those changes to the database.
01:35Now that's all you need to do if you're providing the primary key value.
01:39But if you're working with a database table where the primary key column uses an integer
01:44primary key that auto increments, that is where the next available value is assigned automatically
01:50by the database then JDBC gives you the ability to get that new value right after you execute the update.
01:56Here's how it works.
01:58First you need to find out whether the insert statement was successful.
02:01The executeUpdate method always returns an integer value, the integer is the number of
02:06rows that were affected by the insert and for this kind of insert statement if the execution
02:11was successful it'll always be one.
02:14So I'm going to place the cursor before the call to execute update, and I will declare
02:18a new variable called affected data typed as an int, and I will populate its value from
02:22the executeUpdate method.
02:24Then after the call to the method, I will test whether the execution was successful.
02:28I will use an if else clause.
02:31I will set the condition to affected has a value of 1.
02:35Now if the value is 1, that means that a row is inserted into the database.
02:40In order to get back that value, you're going to need to declare a result set object, and
02:45because of the structure of the try catch block, you will want to declare the result
02:50set object before the try block.
02:52I will move the cursor to above the try, I'll declare a result set object, and I'll name
02:57it keys, and I will initially set it to null, then I'll move the cursor back to the if block.
03:02To find out what the generated primary key value is, call a method called get generated keys.
03:08It'll return that result set object.
03:11So I will type in keys equals, and I will get the results set by calling the statement
03:15objects, getGeneratedKeys method.
03:18It's a result set, and as with all result sets, the cursor starts before the first row of data.
03:24So then I will call keys.next to move the cursor to the one and only row of data.
03:29Now I am ready to get the value.
03:31When you call getGeneratedKeys, you will always get back a result set with a single column and a single row.
03:37So to get the value out, I will declare a variable named newKey, and I will call keyes.getint,
03:43and I will pass in a value of 1 for the first column.
03:47You might be tempted to find out what the name of column is and use that instead.
03:51But the name of that column will differ from one database to the next.
03:55So for maximum portability, just say you are getting it from column 1.
03:59Then I will take that value, and I will pass it to the bean object using bean.setAdminId,
04:03and I will pass in newKey.
04:07Now I am not going to return the bean object, instead I am just setting this property of
04:12the bean object which will also be accessible from the calling context.
04:16So I am going to place the value there, and then I'll get it back later after I have called the insert method.
04:22I'm not done with this method yet, though. First, let's do with the else condition.
04:26If I get into this bit of code, that means that my insert statement was unsuccessful.
04:31So I will do some system error output and output a static string of No rows affected,
04:37and then I will return false which according to the logic of this method, the insert method,
04:42means that this was not successful.
04:44I also need to deal with the keys result set as with all results sets. You need to explicitly
04:49close it when you're done.
04:51So I'll move the cursor down to within the finally block, I will test the keys object
04:55and make sure it's not null, and if it isn't, I will close it.
04:59Notice I'm putting all of this code on a single line because I don't have multiple lines of
05:03code, I'm not using braces, and I am keeping it nice and simple.
05:07This method is now complete, but before I leave it I will point out one little bit of
05:11code that I added previously.
05:13When I call the prepared statement method, I'm explicitly passing in these option statement.return generated keys.
05:20For some database management systems, the statement object will do this automatically,
05:25but for others it won't.
05:26As with all such options where database behaviors will differ, I recommend being explicit in the options.
05:32Here I'm saying no matter what database management system I'm working on, if you're able to return
05:37the generated keys, please do it. So that's the entire insert method.
05:41Now let's add code in the main class to call the method.
05:44I will go to Main.java and with the cursor after the call to display all rows, I'll get
05:49information from the user and pass it to a bean object.
05:53First, I'll create an instance of the Admin bean object.
05:56I will name it bean, and I will instantiate it with the bean class's constructor method.
06:01Now I will set the two properties that I want to add my new database row.
06:06First, I'll call the bean object setUserName method, and I will directly pass in the result
06:10of calling my InputHelpers, get input method.
06:13I will type InputHelper and press Ctrl+Space to add the import then get input, and I will
06:19display a prompt of User name, then I'll do the same thing again.
06:22This time for the password, I will call the setPassword method of the bean object, and
06:27I'll pass in the inputHelpers getInput method again, and this time I'll use a prompt of Password.
06:33Now I'm ready to insert the data into the database.
06:36Remember that the insert method will return a boolean value, so I will declare a variable
06:41that I will name result, and I will call AdminManager.insert, and I will pass in the bean object.
06:47Then I will test the result.
06:48If the result is true, I will do a little bit of system output, and I will output the
06:53string New row with primary key, and then I will append to that bean.getAdminId.
06:58Remember, I populated that value from the inset method and then I will complete the
07:03output with was inserted. And now I am ready to test my application.
07:07I will make sure I have saved all my code, and I will run the application.
07:11I will type in a new user of New Admin, and I will type in a password of New Password.
07:17And I get back the message that the New row with primary key of 2 was inserted.
07:21So to check to make sure that the data was correctly inserted, I will go to my browser,
07:26and I will open up phpMyAdmin.
07:27I will go to my explorecalifornia database to the admin table and browse, and I see my
07:34new row was successfully inserted. So that's how you insert data using JDBC.
07:40You don't have to use JavaBean classes, but as you can see here, to help keep your code
07:44clean and easily maintainable, you encapsulate the data that you want to add into the database
07:50inside an instance of your JavaBean, you pass the bean object from one method to the next,
07:55and then if you need to restructure your database table, you can restructure your JavaBean class as well.
08:00
Collapse this transcript
Updating rows with prepared statements
00:00So far in this chapter I have described how to create the JavaBean class to represent
00:04a single row of data and how the insert new data into a database table.
00:09Now I'll show how to update existing data.
00:12Working in a version of my project called UpdateSQL, I have added a new method to the
00:17AdminManager class. The method is named Update.
00:20It receives a single argument, data typed as the Admin JavaBean, and it has an SQL statement.
00:26The SQL statement follows the standard for all updates in SQL.
00:30It starts with the keyword UPDATE and then the table name admin and then SET,
00:35then there's a series of column name value pairs.
00:38I'll be updating two of the values, the userName and password, and then there is a WHERE clause
00:44that filters the statement so that these changes are only applied to a single row.
00:48This method already has code to create the connection and the prepared statement.
00:52I'll add code now to pass the values from the Bean argument into the prepared statement.
00:58I'll place the cursor after the opening brace and before the return statement and make a
01:02little bit of extra space.
01:04The SQL statement has three parameters, two strings and one integer.
01:08So I'll call the setString method twice and the set int method once.
01:12I'll start with the strings.
01:13I'll call the statement object setString method, I'll pass in a parameter index of 1, and I'll
01:19get the value of the username from the JavaBean object calling bean.getUserName.
01:25Now I'll duplicate that line of code, and for the second version I'll change the parameter
01:29index to 2, and I'll change the method I'm calling to get the value from get.UserName to getPassword.
01:35I'll duplicate it one more time.
01:37And this time I'm going to call setInt instead of setString.
01:41I'm going to be updating this parameter for the adminID, and that's an integer column in the database.
01:47I'll set the parameter index to 3, and I'll call the method getAdminID to get the primary
01:52key value from the JavaBean object. So now my prepared statement is ready to go.
01:57As I did in the previous video with the Insert statement, when I call execute update, I'll
02:02get back in the integer indicating how many rows are affected.
02:05With an update statement where you're filtering on a primary key you should always get back a value of one.
02:11So I'll create a variable called affected, and I will call the statement object executeUpdate
02:15method without passing any arguments. Then I'll check the affected value.
02:20If it has a value of one, I'll return true indicating to the calling scope that the update
02:25was successful, and I'll put in an else clause and return false, because if I get back a
02:30value other than one that means something went wrong.
02:33Now that I have handled all possible cases both the execute update method working and either
02:38updating or not updating a row, my final return true is no longer needed, so I'll delete it.
02:43And that's my completed update method.
02:45So again, to review it, I'm receiving an object a JavaBean object.
02:49I have an SQL statement with placeholders for the values I'm updating and the primary
02:54key I'm filtering on and creating a connection and a prepared statement, I'm setting each
02:59of the values from the bean to the statement and then executing the update,
03:03and then evaluating whether it was successful and returning true or false.
03:08Now I'll go back to my main class, and I'll add code to update an existing row.
03:12In this version of my main class I'm allowing the user to enter a primary key value in AdminID,
03:18and I'm retrieving that single row from the database using the existing method get row.
03:23I'll place the cursor after this if clause.
03:26If I get to this point, then I know I'm working with a valid row.
03:29I'll ask the user to enter a new password value.
03:32I'll use the InputHelper's getInput method, and I'll prompt Enter new password.
03:37Notice I'm only doing this after I have verified that they selected an existing row.
03:42I don't do this before I get the row, because I might not have valid data to work with.
03:47Now I'll take the value that the user entered, and I'll pass it into the bean object using
03:51bean.setPassword, and I'll pass in the new password value.
03:56Then I'll execute the update and check the success of the operation all at the same time
04:00using if AdminManager.update, and I'll pass in the bean object.
04:05And if I get back the true value, I'll do a little bit of system output, and I'll put the line Success.
04:11Then I'll add an else clause and within that section, I'll output an error of whoops.
04:16And now I'm ready to test my code.
04:18I'll run the application, and I'll see that I have an existing row with a primary key
04:23of 2 and a username of New Admin and a password of New Password.
04:27I'll enter 2 as the row I want to update.
04:30I get the prompt to enter the new password, and I'll enter just pwd.
04:34And I'll press Enter, and I get back the message Success.
04:37I'll run the application again, and this will show me the existing data now coming from
04:41the database table, and I see that new value was successfully updated.
04:46I'll try it again, typing in the number of 2, and I'll return it back to New Password,
04:50and I could go over to phpMyAdmin and check it there, but if you're seeing it updated
04:55and displayed each time you run the application here, then you'll have confidence that the
04:59data is being successfully updated in the backend database.
05:04
Collapse this transcript
Deleting rows with prepared statements
00:00After inserting and updating, the third operation you need to know how to do is deleting.
00:06In this version of the project DeleteSQL, my main class is collecting an adminID an
00:11integer from the user.
00:13I'll run the code so far and show that it starts by displaying the data and then I can
00:17enter a value and then nothing happens.
00:20I'm going to add code to delete a row from the existing data.
00:24I'll go to my AdminManager class in this version of the project.
00:27I have created the delete method.
00:29The delete method only receives an integer argument.
00:33It doesn't need an entire JavaBean object, because all it needs to know is the primary
00:37key of the row you want to delete.
00:40As with previous exercises I have seeded this file with the SQL command I'll need, DELETE
00:45FROM and in the name of the table, WHERE and then the primary key column and a placeholder,
00:51which for this table will be an integer.
00:53I'll complete the code by setting the placeholder value.
00:56I'll place the cursor before the return statement, and I'll call this statement objects setInt method.
01:02I'll pass in the parameter index of 1. This SQL statement only has one parameter.
01:07And then I'll pass in the adminId as the value I want to filter on, and that's all I need.
01:12I'll execute the update, but as with the update statement I'll look at the value returned
01:17by the execute update method and integer to find out whether the operation was successful.
01:22I will declare the variable named affected, and I'll get its value from the statement
01:26object's executeUpdate method.
01:28Now remember, the value that's returned from this method represents the number of rows
01:33that are affected by the SQL command.
01:35So if it's 1, that means that a row was successfully deleted, and if it's not 1 that means that
01:41probably the row just didn't exist. So I'll do a little bit of if else programming.
01:46I'll set the condition to affected has a value of 1.
01:49And if that's true, I'll return true, and if it isn't true I'll return false.
01:54And I no longer need to return statement at the end of the method, so I'll delete it.
01:58So that's the entire delete method. I'm receiving a primary key argument in integer.
02:02I'm taking that value and passing into the SQL statement through the prepared statement
02:07object, and I'm executing the command.
02:09And then I'm evaluating whether it was successful and returning either true or false.
02:14I'll save those changes and go to my main class.
02:16I'm already getting the value of the primary key of the row I want to delete.
02:21So all I have to do is call my new delete method.
02:24I'll create an if else block, and I'll call AdminManager.delete.
02:28I'll pass in the adminId variable, the value the user provided, and if that value is true,
02:34I'll output a Success message.
02:38And if it's false, I'll output an error of nothing to delete.
02:43And now I'm ready to test my application.
02:46I'll run, I see the existing data has two rows, the original row that I seeded the database
02:51with and a row that I inserted in a previous exercise.
02:55I'll pass in the primary key of the row I want to delete, the second row that I just inserted previously.
03:00I'll press Enter or Return, and I get back the message Success.
03:04Now I'll run the code again right away, and I'll see that that row is gone, but I'll try
03:08to do it again just to make sure that the logic of my application makes sense.
03:13And now because the affected value returned from execute update is zero, that is, no rows
03:19were affected, I returned false from that method, and in the main code I output the error
03:24message Nothing to delete.
03:25So the process of creating, updating, and deleting data with SQL statements is all pretty much the same.
03:32You can manipulate your database with whatever SQL commands you know and that your database supports.
03:38I have kept things really simple in these demonstrations doing plain vanilla inserts, updates, and
03:43deletes that would be accepted by all databases.
03:46But again, you can use what ever SQL Syntax your Database Management System supports.
03:51That SQL is passed directly from your application through the JDBC driver to the database where it's actually processed.
03:59And as I have previously shown, you can choose from either SQL statements embedded into code
04:04like this or stored procedures that are built directly into your database.
04:09
Collapse this transcript
Managing data with updatable result sets
00:00I have shown so far how to do inserts, updates, and deletes using SQL statements and the prepared statement object.
00:08There's an alternative in JDBC the updatable result set, where you get a result set from the
00:13database and market as updatable, then change the data directly in the result set.
00:18You can do inserts, updates, and deletes with this approach.
00:21Whether it's a good idea depends on your circumstances and your database management system.
00:26Not all database management system supports updatable result sets, and if you're working
00:31with a very large result set, it can cause performance issues.
00:35But in a small-scale application, or when you're only dealing with one row at a time, an updatable
00:40result set programming approach can be useful, I'll demonstrate how to update a row of data
00:45using an updatable result set. I'm working in a project called UpdatableRS.
00:50The state of this project is similar to the update exercise that I did previously, there
00:54is an update method with an SQL statement, it has three placeholders, two strings for
00:59the username and password, and one integer for the admin ID, a prepared statement is
01:04being used and executed to make the update.
01:07I'm going to change this code to use an updatable result set instead.
01:12First, I'll change the SQL statement.
01:14Instead of an update statement, I'm going to use a select, it'll look like this SELECT * FROM
01:19admin and then I'll filter on the primary key that's been passed in as part of the bean object.
01:27In my SQL statement I'll create a placeholder for that value.
01:31Next, I'll go to my prepareStatement method, this is where you'll mark the result set as being updatable.
01:36I'll make a little bit of extra space by moving the SQL parameter down to the next line, then
01:41I'll add two more arguments.
01:43First, ResultSet.TYPE_SCROLL_INSENSITIVE and then ResultSet.CONCUR_UPDATABLE.
01:50This is called the concurrency setting of the result set object, because I have set it
01:55as updatable I can now make direct changes to the result set object.
01:59My SQL string now only has one placeholder, so I no longer need these two strings, I'll comment them out.
02:06And I'll change the parameter index for my final setting to one, so now I have prepared
02:11the statement, and I'm going to retrieve the data from the database.
02:15Instead of executeUpdate, I'll be using executeQuery, the same method that I have used previously to retrieve data.
02:21And instead of returning an integer, it's going to return a result set. Because I'll be manipulating
02:27this result set within my try block, I'll first declare it outside the try block and then close
02:32it in a finally block.
02:33I'll move the cursor up to above the try block and declared the result set, making sure to
02:38import the version from java.sql, I'll name it RS and set it initially to null.
02:43Then I'll move down to below the try catch block and add a finally block and within the
02:48finally block I'll check to see if it's still null, and if it isn't, I'll close it.
02:53Then I'll go back to the call to statement. executeQuery, and instead of getting an integer, I'll be getting back the result set.
02:59I'll delete these remaining three lines of code, they no longer apply, and now I'll add an if else clause.
03:06In order to modify the data that I just retrieved, I have to move the result set cursor onto the row of data.
03:13So I'll add an if and an else block, and I'll set the condition to rs.next, moving the cursor
03:19to the only available row of data.
03:22Now I'll update the columns that I want to change.
03:24Even though my application is only going to update the password for the current row, this
03:30code doesn't know it. This code should be written so that it updates every column in
03:34the database row other than the primary key.
03:36So I'm going to call the update string method a couple of times.
03:40You'll see that there are update methods for all the various data types that a database
03:44supports, I'll call updateString, and as with all of the other methods the sets and the
03:49gets and similarly to the get methods that are a part of result set, you can reference
03:54a column either by its index or by its name.
03:57I'll choose the version that looks for the name, and I'll pass in username,
04:01and then I'll set the value to bean.getUserName.
04:04I'll duplicate that line, and for the second version, I'll set the column name to password,
04:09and I'll call the bean objects getPassword method.
04:12Once I have set those values, I have to commit them by calling a method called updateRow.
04:17Notice that there are a few different versions. Because I have already made sure that the cursor
04:22of the result set is on the right row, I can use the version of this method that's the
04:26simplest, the one with no arguments.
04:28Then because I have gotten through all this code without throwing an exception, I can assume
04:32that the update was successful and return true.
04:36And if the next method return false, that is if there was no data to update, I'll return false.
04:42So this is the final version of the update method using an updatable result set.
04:46You'll see that you aren't saving any code by going with this approach, but some developers
04:50prefer this to doing update statements. It's really up to you, and whether it works well
04:55within your database management system is a matter of a lot of different factors.
04:59If you're not sure whether this is a good idea with your database management system,
05:03chat with other developers who have used both the updatable result set and classic SQL statements
05:09with your database. But let's complete the exercise.
05:12I'll save the changes, and I'll go back to my main class.
05:15I'm not going to change anything about the main class.
05:18From the main classes point of view, everything should work exactly the same.
05:21I'm accepting a primary key value from the user, I'm retrieving a row of data as a Java
05:26bean object, I'm applying a new value to the password, and then calling the update method
05:32of the admin manager class.
05:33I'll run the code, I see that I only have one row in the database right now, so I'll
05:38type in the primary column value of one, I'll enter a new password of new pwd, and I'll
05:44press Enter or Return, and I get back the message Success.
05:47And if I run the application again, I'll see that the value is correctly updated in the backend database.
05:53So it's your choice, updatable result sets or classic SQL statements.
05:58Either way you'll be using the prepared statement object to put your code together, and it's
06:03really up to you which style you prefer.
06:08
Collapse this transcript
Using a persistent database connection
00:00If you have been working through the exercises in this video series, you might have noticed
00:04that we're opening a lot of database connections.
00:07I'm working in a version of my project called ConnectionManager that has the code for updating a database table.
00:13And I'll go to the tables package and open AdminManager.java.
00:17The way this application is currently architected every time I call my DBUtil class's getConnection
00:23method, I'm opening a new connection, and then I am closing that connection when that method is finished.
00:29And if you count up all the times that we are using the get connection method, you'll
00:32see that we're opening and closing connections many, many times.
00:35In JDBC this is into great practice, and that's because connections are expensive.
00:40They take time, memory, and resources, and so to the extent possible you should minimize
00:46the opening and closing of connections by reusing connections.
00:50When you work in a Java Enterprise Edition Server environment such as JBoss, the server
00:54typically will provide connection pooling.
00:57It's a multi-user environment, and so it's vital that multiple users reuse those connections.
01:03If you're building your own Java application, though, either as a console application like
01:07this or a desktop application, you might need to write your own logic.
01:12In this project, I have provided a bit of code called the ConnectionManager.
01:16The ConnectionManager class is a singleton, a class that can only be instantiated once.
01:22This is a common design pattern in Java, and it's used whenever you want to make sure that
01:26your entire application is using the same object.
01:30The ConnectionManager starts with a private static instance of itself, and the name of
01:35that field is simply instance. It's initially set to null.
01:39It then contains String fields for all the credentials we'll need to connect to databases
01:43and a DB type field which is not static.
01:46So it can be changed after this class is instantiated.
01:49There is a private field for the connection object, and there's only one, and it's initially set to null.
01:55Now here is the code that manages the singleton aspect of the class.
01:59The goal of a singleton is to make sure that the entire application can get a reference
02:04to it, but it can only be instantiated once from within the class itself.
02:08And so we control that with a private constructor.
02:12When you mark the one and only constructor method as private, that means that it can
02:16only be constructed from within this class.
02:19And then there is a static method called getInstance which checks to see whether the one instance
02:24is null, and if it isn't, it instantiates it, and then either way, it returns it.
02:31So to get a reference to the one and only ConnectionManager object for the whole application,
02:35other parts of the application will call the static method ConnectionManager.getInstance.
02:41Let's take look at the rest of the code.
02:42There is a public method called setDBType that lets the application decide what type
02:48of database we're going to use either MySQL or HSQLDB.
02:52There is a private method called openConnection.
02:56We'll only call this method if the connection isn't already open, but it looks exactly the
03:01same as it did in our DBUtill class.
03:03It checks the database type and then uses the appropriate logic to open either MySQL or HSQLDB.
03:09There is public method named getConnection.
03:13This method will be called from the one and only instance of the ConnectionManager.
03:17It checks to see whether the one and only connection is null, and if it is it opens
03:21it and then it returns the reference.
03:23And if the code gets all the way down to this line, it returns the already open reference.
03:29Finally, there's a close method. Remember that you should always explicitly close your connections,
03:34and using a singleton manager makes no difference.
03:37So now the singleton manager is responsible for closing the connection.
03:40And in this case, it both closes it and sent it to null so that we can explicitly manage
03:45the opening and closing of the connection from anywhere in the application, but only
03:50by calling this method.
03:51This code is fairly intensive, and if you don't have access to the exercise files, I
03:56don't want to make you type it out.
03:57So I have provided this project in the code section of the free exercise files.
04:02Now let's see how we can use the ConnectionManager class.
04:06I'll go to my main class.
04:07The first thing I'll do is set the database type, either HSQLDB or MySQL.
04:13I'll place the cursor after the comment.
04:16Now I'll get a reference to the ConnectionManager object and set the database type.
04:20I'll say ConnectionManager.getInstance, and that gives me the reference to the ConnectionManager,
04:26and from there I'll set the database type with DBType.MYSQL.
04:31I'll also add code at the end of the method to ensure that the connection has been closed,
04:36and that'll look like this ConnectionManager.getInstance().close.
04:41So that's all I have to do from the main class, I set the database type and make sure the
04:45connection is closed. Now let's go to the AdminManager class.
04:49The AdminManager class is where we have all these calls to the getConnection method, and
04:54we're opening and closing the connection over and over.
04:57I'm going to change the model for this.
04:59I'm going to create my connection as a static field of the AdminManager class.
05:04I'll place the cursor inside the class declaration, but before any of the methods, and I'll declare
05:09a private static Connection, and I'll name it conn, as it's been named previously.
05:14And I'll get its reference by calling ConnectionManager.getInstance().getConnection.
05:20So now the first time any of these static methods are called, this static connection
05:24object will get its reference automatically.
05:27And I can go through all the rest of the code, and I can comment out or delete all of the
05:31other code that's getting the referenced from the DBUtil class.
05:35I'll delete it from the getRow method, I'll keep on scrolling down, and I'll delete it
05:40from the Insert method, and also from the Update method.
05:44I'll save my changes, and I'll go back to my main class, and I'll run the code again.
05:48And because I have system output scattered throughout the application, I'm able to see
05:53the order in which things are happening.
05:55First, I get the message that the application is starting then the message that the connection is opened.
05:59Now, notice I still have input that I have to provide, and if things are working,
06:04the connection is still open.
06:06So I went to the number one and a new password, and I get back the message Success.
06:11And then I see the message that the connection is being closed, because I get to the code
06:15in the main method that calls the close method of the ConnectionManager.
06:19So, now I'm using a single connection to my database.
06:23I'm saving memory, time, and resources.
06:26Again, if you're working in a Java Enterprise Edition Server environment, you'll have a connection
06:31pooling architecture that the server provides.
06:34But if you're working on a Console or a desktop application, it's up to you to write this
06:38code, and this is one possible model that you can try out.
06:43
Collapse this transcript
Committing and rolling back transactions
00:00A database transaction is one or more actions that are making changes to data in a database
00:05server or local database file.
00:08Whenever you make changes such as inserts, updates, or deletes, you're creating transactions.
00:13And in JDBC, these transactions are what we call auto-committed.
00:17That is, if you don't see anything else, the changes that you request are made and committed
00:22to the database immediately.
00:23But most database management systems give you the ability to explicitly commit and roll back transactions.
00:29It depends on what database you're using, and how you're using it.
00:33For example, with MySQL, it depends on what backend database engine you are using.
00:38I'm going to go to phpMyAdmin to my Explore California database, and I'll choose one of
00:43my tables, the admin table, and I'll go to the Operations tab.
00:47Notice that the storage engine for my database tables is innoDB, and I have specifically selected
00:53that because innoDB supports transactions, row-level locking foreign keys, and other advanced database functionality.
01:01If I had chosen the default database type MyISAM, I would not have gotten many of those
01:06features, including transactions.
01:08But innoDB does support transactions, and so I'll be able to demonstrate how JDBC handles
01:13transactions with this sample database.
01:16I'll go back to Eclipse where I'm working with a version of my project called Transactions.
01:21This is a version of my update application where I'm asking the user for a primary key
01:26value, and then a new password, and I'm updating the database at the server level.
01:32I'll expand my editing window and then run the application.
01:35I'll type in a number of an existing row and a new password.
01:39I get back a message saying I have succeeded and that the connection has been closed.
01:43Then I'll run the application again and show that the new password was successfully updated,
01:48and I'll stop the application.
01:50Now, again, the reason the change was made is because my transaction is auto-committing.
01:55But here's how you can change your connection so that it doesn't auto-commit.
01:59I'll need a reference to my connection, and right now my connection is being managed
02:02by my Singleton ConnectionManager class.
02:05I'll place the cursor before the call to the update method, and I'll create a reference
02:09to my connection object with Connection conn = ConnectionManager.getInstance().getConnection().
02:16I will make sure I have included an import for the connection interface in Java.SQL.
02:20Now I'm going to set the autocommit property to false with conn.setAutoCommit, and I'll
02:27pass in a value of false. So far, so good.
02:31Now when I go to the update method, this is where the SQL statement is being processed and executed.
02:37And previously, when the connection object's AutoCommit property was set to the default
02:42of true, the change was made and committed to the database when the executeUpdate method was called.
02:47But now that I have set AutoCommit to false, that's no longer the case, and I have to explicitly commit the change.
02:53So I'll go back to my main class, and down here I'll call conn.commit, and then I'll
02:59do a little bit of system output, and I'll output the message Transaction committed,
03:04and I'll test my code again.
03:05Once again, I'll type in the row number and another new password.
03:09This time I'll just use pwd.
03:10I get back the message, Success, and that it was committed.
03:13Then I'll run the application again to see the data, and I'll see the change was made.
03:17But now let's change that logic so that we're rolling back the connection.
03:21I will change from commit to rollback, and I'll change the message to indicate what I did.
03:27I'll run the code again, I'll type in the row number and new password,
03:32and I get back the message that the update method call was successful but that I have rolled back the transaction.
03:37So, now I'll run the application again, and I'll see that the change was not made.
03:41I still have the old password of pwd.
03:44So, once you have set the connection object's AutoCommit property to false, you can then
03:49explicitly commit or roll back your transactions as you need to.
03:52The specific logic of your application will differ depending on the type of application
03:57and your reasons for rolling back transactions. But the code is pretty simple to use.
04:02Just make sure that you have set AutoCommit to false, that you're using a database management
04:06system that supports transactions, and that you're calling the commit or rollback methods
04:11in the appropriate places of your application.
04:16
Collapse this transcript
6. Using Metadata
Getting the DatabaseMetaData object
00:00In most database application environments, you already know the database structure, the
00:05names of the tables, the number, and types of the columns, and so on,
00:09but there are times when you have to discover this information dynamically, and JDBC gives
00:14you that ability through a function called metadata.
00:17The term metadata in the context of databases describes exactly the sort of information,
00:23and you can get the metadata from a database connection quite easily.
00:26I'll do an initial demonstration of this functionality in a project named Table List.
00:31I'm using a Singleton Connection Manager which I have described how to build in a previous exercise.
00:37I have gotten a reference to my connection, and then within the try catch block, I'm going
00:41to add some data to get a list of tables that's in my database.
00:46Within the try block, I'll first declare an object instantiated as DatabaseMetaData.
00:52As with many other objects in JDBC, you might see more than one version.
00:56Always be sure to choose the version from java.sql for maximum portability.
01:01I'll name this object metadata.
01:03Then I'll get its reference from the connection object's getMetaData method.
01:07You'll see a couple of versions listed, but in fact, there is only one.
01:11The getMetaData method takes no arguments.
01:14I'm going to interrogate this object to get a list of tables.
01:17There are actually many different types of tables in a database.
01:21But the only ones I'm interested in are the ones that contain my data.
01:24And there's a series of database types that I can select from.
01:28To control which database table names are returned, I'm going to create an array of
01:33strings, and I'll name it tableTypes, and I'll declare the array as a pair of braces,
01:39and I will only have it contain one item.
01:41All database management systems should support this table type,
01:46but the number and names of the different table types will then vary from one database
01:50management system to the next.
01:52Now, I'm going to get the list of tables. It's going to come back as a result set.
01:56I'm going to name the result set RS Tables, and to properly manage it, first I will declare
02:01the result set outside of the try catch block.
02:04I'll declare it with a data type of ResultSet, then rsTables as the object name, and I'll
02:10initially set it to null.
02:12Then within the try block, I'll instantiate it with rsTables=metadata.getTables.
02:19The getTables method takes four arguments, the catalog which is the name of the database
02:25which I have already selected in my connection string, so I don't need to pass it in again.
02:29I'll set that to null, the schemaPattern which I'll set as a wildcard of a percent sign,
02:35the tableNamePattern which I'll also set with a percent sign wildcard, and the tableTypes
02:40which will be my array of strings that I already created.
02:44The result set will come back with a column named table_name.
02:48So now, to print out the list of tables, I'll create a while loop, and I will iterate with a condition.
02:54The condition will be rsTables.next.
02:57So I am going to be moving forward through the ResultSet and working with each row one at a time.
03:02Then within the while loop, I'll use system output, and I'll output the value of rsTables.getString,
03:09and I'll pass in the name of the column TABLE_NAME.
03:12When I'm done, I'll need to close the result set.
03:15As with all result sets, you will typically do this in a finally block.
03:19So I'll move the cursor there and call rsTables.close.
03:23I'll save my changes and run the code, and there is my list of tables in my backend database.
03:28You're able to do a lot more than this with the database metadata, including finding out
03:33about columns, their names, and their datatypes.
03:36I'll show you how to do some of these other tasks in another video.
03:41
Collapse this transcript
Getting column and data type information
00:00I have previously described how to use the database metadata class to get a list of tables from a database.
00:06I'm working in a new version of that project named TablesAndColumns where I already have
00:11the code to get the list of tables.
00:13I'll test it and make sure that I'm successfully retrieving that information.
00:17Now I'm going to show you how to get more information from the metadata object, including
00:21the names and data types of the database columns.
00:25I'll start by re-factoring this code.
00:27Instead of immediately outputting the name of each table, I'm going to store the names
00:31of the tables in an array list.
00:34I'll start by declaring an array list at the top of the code, I will place my cursor before
00:38the try catch block, and I will declare my ArrayList, and I will set its data type to
00:44String, that is that's the data type of the items it will contain.
00:47And I will name it tables.
00:49I will instantiate it with the ArrayList class's no arguments constructor.
00:53Now I'll go down to the while loop, where I am looping through the result set of the tables.
00:58I'm still going to need the names of the tables, so I'll select that code and copy it to the
01:03clipboard, and then I'll delete that line.
01:06Then I'll replace that code within the while loop with a call to the array list add method
01:11using tables.add, and I will paste in that code that was getting the table name already.
01:17So now I have a resizable array, an array list containing the names of the tables, and
01:22I can loop through that and get the columns for the tables one at a time.
01:26To contain that information, I'm going to need another result set.
01:30So I will move back up to where I'm declaring my local variables within the main method,
01:35and I'll declare another result set, this one called rsColumns, and I will initially set it to null.
01:40Now I will move back to after the while loop, and I'm ready to process the tables.
01:45I will make some extra space.
01:46And to loop through the array list, I'll use a foreach code template.
01:51I'll type in foreach and press Ctrl+Space, and I'll choose that code template, and I
01:56will name the variable that's going to be generated each time through the loop, tableName.
02:01I'm going to be looping through the tables collection.
02:03So I will make that change as well.
02:06On each time through the table, I will first output the name of the table.
02:10I'm going to need three system output lines.
02:13So I will type in System.out and press Ctrl+Space, and then I will duplicate that line a couple of times.
02:18For the first system output, I will output the name of the table prefixed with a label.
02:23I will type a label of Table: and a space, and I will append to that the tableName.
02:29The second output will be a string of dashes, that will separate the tableName from the
02:34columns, and the third one will just be a blank string, and I will output in the column names
02:39before that blank string, so I will make some extra space there and here is where we will
02:44put the code to get the list of the columns.
02:46I have already declared my result set where I will contain the list of the columns.
02:50I named it rsColumns. So now I will get its reference.
02:54I will use rsColumns =, then just as I did for the tables, I will use a method of the metadata object.
03:01It will be metadata.getColumns.
03:04The getColumns method is very similar to the getTables method.
03:07It asks for four arguments.
03:09As with getTables, the catalog can be left to null because I have already designated
03:14the catalog or database I am working with in my connection string.
03:18The schemaPattern can be set to a wildcard.
03:21The tableNamePattern should be the specific table that you are querying.
03:25So I'm going to pass in my variable tableName and the columnNamePattern can be a wildcard
03:31because I'm asking for all of the columns for the current table.
03:35So now my result set will contain all of the information I need about my columns.
03:40The result set will contain a bunch of columns, and you should take a look at the documentation
03:44for this method to see what the column names are, but the particular column names I'm interested
03:49in are called column_name and type_name.
03:55I'm going to loop through the result set using a while loop with a condition.
03:59I will set my condition to a call to the rsColumn.next method.
04:04That will be rsColumns.next. Within the loop I will create a StringBuffer.
04:08I will name it buffer, and I will instantiate it with the no arguments constructor.
04:13I'll start by appending the name of the column, I'll use rsColumns.getString, and I will pass
04:19in the name of the column which will be COLUMN_NAME.
04:24I'll duplicate that line of code, and I'll change the second one from COLUMN_NAME to TYPE_NAME.
04:30And in between, I will separate these bits of output with a colon and a space.
04:35Finally, I'll add some system output, and I'll output the value of the two string method of the buffer object.
04:41I will clean up the extra white space, and now I'm ready to test my application again.
04:46Let's review the code. I'm looping through the array list of tables.
04:50On each time through the loop I am outputting the name of the table and a separator string.
04:54Then I'm getting the list of columns just for that table and then I'm doing another
04:58loop, this time through the result set of columns.
05:00I create a string buffer, and I append to that the name of the column, a separator and
05:05the name of the datatype and then I output that information.
05:09I'll move the cursor down to the finally block and do one last little bit of cleanup.
05:13I will close the rsColumns object, and now I'll run my code, and I get back exactly the
05:18list I am looking for.
05:20For each table, I'm displaying the name of the table and then after the separator the
05:24names and data types of each of the columns.
05:27As I have mentioned previously, look at the documentation for the getColumns method, you'll
05:31see a listing of all of the names of the columns that are returned in this result set.
05:36You'll find that you can get the names of the columns, the lengths of the columns, and
05:40all of the other information you might need and look thoroughly at what else is available
05:45in the database metadata object, it will return information about stored procedures, functions,
05:51and pretty much everything that you have stored in your database.
05:56
Collapse this transcript
Conclusion
Next steps
00:00Thanks for sitting with me through this video series Java Database Integration with JDBC.
00:05In this series, I described how to work with relational database management systems using the JDBC API.
00:12JDBC is at the core of nearly every database interaction you might need in Java, so regardless
00:17of whether you're building desktop applications or web applications that are hosted on Java
00:22enterprise edition servers, JDBC will be one of the foundations of those applications.
00:27To learn more about other aspects of Java, check out the course, Java Advanced Training.
00:33And to learn more about object-oriented programming in general, I recommend watching
00:37Foundations of Programming: Object-Oriented Design.
00:40I hope this course has helped you get ready to build your own Java-based data driven applications.
00:46Thanks again for watching and happy programming.
00:51
Collapse this transcript


Suggested courses to watch next:

Java Essential Training (7h 17m)
David Gassner

MySQL Essential Training (2h 46m)
Bill Weinman


Installing Apache, MySQL, and PHP (2h 43m)
David Gassner

Java Advanced Training (3h 33m)
David Gassner


Are you sure you want to delete this bookmark?

cancel

Bookmark this Tutorial

Name

Description

{0} characters left

Tags

Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading
cancel

bookmark this course

{0} characters left Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading

Error:

go to playlists »

Create new playlist

name:
description:
save cancel

You must be a lynda.com member to watch this video.

Every course in the lynda.com library contains free videos that let you assess the quality of our tutorials before you subscribe—just click on the blue links to watch them. Become a member to access all 104,141 instructional videos.

get started learn more

If you are already an active lynda.com member, please log in to access the lynda.com library.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Access to lynda.com videos

Your organization has a limited access membership to the lynda.com library that allows access to only a specific, limited selection of courses.

You don't have access to this video.

You're logged in as an account administrator, but your membership is not active.

Contact a Training Solutions Advisor at 1 (888) 335-9632.

How to access this video.

If this course is one of your five classes, then your class currently isn't in session.

If you want to watch this video and it is not part of your class, upgrade your membership for unlimited access to the full library of 2,025 courses anytime, anywhere.

learn more upgrade

You can always watch the free content included in every course.

Questions? Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com.

You don't have access to this video.

You're logged in as an account administrator, but your membership is no longer active. You can still access reports and account information.

To reactivate your account, contact a Training Solutions Advisor at 1 1 (888) 335-9632.

Need help accessing this video?

You can't access this video from your master administrator account.

Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com for help accessing this video.

preview image of new course page

Try our new course pages

Explore our redesigned course pages, and tell us about your experience.

If you want to switch back to the old view, change your site preferences from the my account menu.

Try the new pages No, thanks

site feedback

Thanks for signing up.

We’ll send you a confirmation email shortly.


By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

Keep up with news, tips, and latest courses with emails from lynda.com.

By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

   
submit Lightbox submit clicked