JDBC App learning by ex 2

	public void writeProperties() throws IOException {
		Properties prop = new Properties();
		prop.setProperty("dbUrl", "localhost");
		prop.setProperty("dbUser", "username");
		prop.setProperty("dbPassword", "password");

		try (OutputStream out = new FileOutputStream("project.properties")) {
			prop.store(out, "Database Properties File");
		}
	}



	public void readProperties() throws IOException {
		try (InputStream in = new FileInputStream("db.properties")) {
			Properties prop = new Properties();
			prop.load(in);
			dbUrl = prop.getProperty("dbUrl");
			dbUser = prop.getProperty("dbUser");
			dbPassword = prop.getProperty("dbPassword");
		}
	}	

- [Narrator] Our next step is to connect to a relational database. This section is a very quick overview of how to access relational databases using Java. At the end of this video, I'll give you some tips on where to go to get more information. The Java API we use to connect to databases is called JDBC. Which stands for Java Database Connectivity. It's included with the Java Runtime, and it's generic enough that you can connect to many different types of databases with the same or very similar code. You also need a JDBC driver that's specific to the type of database you want to connect to.

The Java JDK on Windows ships with a driver for Apache Derby databases. Oracle calls this Java DB. So if you want to create or use Derby databases there's nothing extra you have to download. At least not on Windows. If you're not on Windows, or if you want the very latest Derby driver from Apache, you can download it from the apache.org website. For other database types, like Oracle, DB2, MYSQL, you need to download the JDBC driver from the database vendor, and then install it. That's a pretty easy process though.

Because in this case, installing a JDBC driver just means making sure the driver's jar file is on your classpath. So all you normally have to do is copy a jar file to your local machine and then make sure the local file is on your classpath when you run the Java application. At the end of this chapter, I'll discuss how to package a driver file inside the jar file you used to distribute your Java application. This gives you the option to ship your application with the JDBC driver file already included. Something else you need to be aware of is license files.

Some of the larger enterprise database vendors require you to have a license file. Which is usually packaged as a separate jar file in addition to the JDBC driver file. Check your vendor's documentation for details on whether this is required for you. The general process for connecting to and using a JDBC database is, make sure you have the JDBC driver on your classpath. Register the JDBC driver with the driver manager. Connect to the database, use SQL queries to put data in or get data from the database, and then close the database connection.

We've already talked about driver files. So let's continue on with a short discussion of how to connect to a database. And some example code. We'll be using the Apache Derby driver for our example. I've already downloaded it from the Apache website, and copied it to our Eclipse workspace folder for this project. To make sure it's on the classpath for Eclipse, I can right click the project and choose Build Path, Add External Archives. This brings up a dialogue that allows us to select the Derby.jar file. Select that file and click Open.

Heading this file to our build path tells Eclipse to put it on the classpath when we compile and run our code. This way we don't have to manage the classpath manually with commandline arguments. Eclipse handles all that for us. There are two general ways to make a database connection. The first is to ask the driver manager class to make a connection using a specially crafted URL. For example, here's our connected database method. You'll notice a few things here. First, we're using a properties object to pass connection information when we make the connection. This is exactly the same kind of properties object we saw before when we were at a properties file.

But this time, we create the object directly in memory instead of reading it from a file. Second, you can see I have a comment regarding driver registration. Some drivers are automatically registered by the driver manager when they're put on the classpath. But, some older drivers require explicit registration. If your connection doesn't work, you might need to call the register driver method first. It generally doesn't hurt to call this, even if it's not needed. Third, the call to get connection has an odd looking string for connecting to the database. That's a JDBC connection string.

Those always start with JDBC, followed by the JDBC driver type, in this case it's Derby. This corresponds to the Derby driver file we just registered. The last part of the JDBC connection string is vendor specific. Here we're just pointing to a local file, so we have a relative file path.The vendor specific part of the string almost always starts with the location of the database. In this example, it's just a file name. But, if you're connecting to a server, the file name usually starts with a URI, specifying the server name and port.

Then there are additional parameters you can specify after the file name. In this case, we have the extra parameter of create equals true. Which tells Derby to create the database if it doesn't already exist. Every JDBC driver has different options for the JDBC connection string.Make sure you figure out the correct syntax for the driver you use. Of course, we shouldn't be using hard coded strings here, right? We already read some data from a properties file, and created some string constants to access it. Now we can make the code a little bit nicer like this.

Instead of specifying the user name jsmith, we can get it from our properties file.GlobalProps.getProperty. And we have the constant values for all of our keys. In this case I'll use db user. We can do the same thing for the password. And we can also get the property for the JDBC URL down here. The other way to access a database is to use a data source to make a connection.

Like this. If you're building multi-user applications, like a J2EE app on a server, it's almost always better to use a data source instead of the driver manager. Data source connections can use connection pooling. And these are much better suited for multi-user and long running applications. For us it doesn't matter, because we're developing a single user app with a very short lifespan. Both the data source and the driver manager techniques return the same type of connection object. So no matter how we connect, the rest of the code we use will be the same. The logic of creating a connection using a data source is simple.

Create the data source instance, set the parameters, then make the connection. It's also possible to set up a connection pool. So instead of getting a data source instance directly,you get it from the pool. We won't cover that here, but that's one of the compelling features to using data sources instead of the driver manager. Sharing database connections in a pool and reusing them can be much more efficient in some circumstances. Also notice that we're explicitly setting auto-commit to true after we get the connection. Normally auto-commit is always set to true after you make an initial connection.

But, if you do get a data source from a connection pool, there's a small possibility you can getan old connection that has auto-commit turned off. That's a pretty rare occurrence. But I like to set auto-commit to true just to be safe. Okay, we've connected to a database. Now we need to write some data, or read some data. We do this using SQL statements. I don't have time in this chapter to go into details about SQL and how it works, and all the different things you can do with it. That could be an entire course unto itself. But I will show you how to make some calls. If you want to call some SQL statements directly, you can do it like this.

That's a SQL statement that will create a new table with three columns. The process is, create the statement object, execute the SQL, and close the statement. You always want to make sure you close your statements to avoid memory leaks. So a better way to write this might be,with a try catch block. And a finally block to close the statement. This will make sure the statement always gets closed, even if we have an error with the execute update method.

Even better, with Java seven and higher, you can take advantage of the fact that JDBC statement objects implement auto closable. And then you can do this. This is a try with resources block that auto closes the statement at the end of the try block. It's like an invisible finally section that closes the statement for you. Even if you get an exception. Here's an example of writing data to the database using SQL. This time we're using a prepared statement to run the same SQL statement multiple times with different parameters. This is much more efficient that creating the same SQL statement over and over.

You can see that the statement has question marks as placeholders. Then we can use setInt, setTimestamp, and setString to add parameters. And finally we can call execute update to run the statement against the database. You need to make sure that the prepared statement gets closed when you're done, just like the regular statement object. In this case, it will be auto closed when the try block finishes. However, in some applications you might create global prepared statements when your class gets loaded, and then use them over and over at different points in your application. If you do that, make sure you have a way to close all your prepared statements before the application finishes.

You would probably do that in the same method you used to close the database itself. One more SQL example. This time reading data. In this example, instead of running execute update, like we did before, we're running execute query. And returning a result set. We're still using a statement to run the query, and we can always make it a prepared statement if we need to run in multiple times through the lifespan of our application. To get data from the result set, we call resultset.next, this gets the next result.

And then we call getInt, getString, and getTimestamp, to fetch data from the various columns.Notice that the first column in the result set row is numbered column one. Not column zero.This SQL query I ran here is just select star from table. So I'm getting all of the records. But the query can obviously be much more complex with where clauses, joins, and all of the other wonderful things that SQL can do. Again, I don't have time to go into depth about SQL as a language here, but you do need to learn it if you work with relational databases. The important part right now is knowing how to actually run a SQL statement and get the results back.

Finally when we're done, we need to close the database connection. We do it like this. If you're connecting to an actual database server, which is almost always how you do it in production, all you have to do is call connection.close and you're done. So you could get rid of all of this if you want to. In this case, since we're opening a file on the local machine and connecting to it directly using the embedded driver, we also need to take the additional stepof sending a shutdown statement. This unlocks the file so we can use it again later. Notice how I'm catching a few specific SQL exception error codes here.

Derby will always throw an exception with an error code 4500 when you call shutdown on a database. Even when the call is successful. I have no idea why, it just does. We could ignore this error, as I mentioned in the comments. This brings up an important point about SQL exception error codes. JDBC drivers can generate SQL exceptions with specific state codes and error codes that are great for programmatically determining exactly what the nature of your error is. It's very helpful to report the codes along with the exceptions in your error handling routines.

Because those can be really useful in troubleshooting. We can test all of this pretty easily with our test connection method. This does all of the things we've talked about so far, reading properties, connecting to a database, reading and writing data, and then closing everything when we're done. Let's call this from the main method and make sure it works. I'll create a database test object here in the main method. And then I'll call test.testConnection. This throws a few exceptions and so we'll need to surround that in a try catch block.

Now let's run this and see what happens. Here's all of the data that got written to the database. And if we had gotten an error we would have seen this in the console. I know that was an incredibly fast run through of how to use JDBC, and obviously there are still a lot more things to learn and understand about how it all works. Here are a few places to get started if you want a deeper dive into JDBC. There are two video courses you might want to look at, "Java Database Integration with JDBC", and also "SQL Essential Training". The PDF I link to here is a Java one presentation that has great information about using Java DB and also JDBC within Java code.

And finally, there's a Java tutorial on JDBC on the Oracle website. I should also mention that JDBC is not the only game in town when you connect to databases using Java. There's also a technology called the Java Persistence API, or JPA for short. And that's very commonly used by Java Enterprise Edition applications. If you're writing applications on a J2EE server, or you're using technologies like Hibernate or Spring, then you'll be using JPA to interact with databases instead of JDBC. Here are a few links to visit if you want to learn more about that.

- [Narrator] Next on our list, is to have a short discussion about Java cryptography and using it to encrypt and decrypt strings. Java has an impressive amount of support for general cryptography built into the run-time as part of the standard class libraries. The overall set of classes that provide cryptography functionality is referred to as the Java Cryptography Architecture or JCA for short. The classes themselves are divided between the java.security package and the javax.crypto packages. In this section, we're going to cover a very specific piece of functionality.

Encrypting and decrypting a string with a known password. But there are a lot of other really cool things you can do like public key encryption, hash function, signatures, and certificates. If you want to use crypto in your application, Java already has a lot of things you can use. In the first section of this chapter, I mentioned how it was a really bad idea to keep our database passwords stored inside a plain text file. Obviously passwords are super secret things and we shouldn't just leave them laying around in the open. If you have to deal with passwords in your applications, the very best thing to do is not store them at all.

Just prompt the user for the password every time you need it. If you prompt the user for a password and then store it for the lifetime of your application, maybe because you have to reuse it and you only want to ask the user once, then you should take care to store the password in a character array instead of a string. That sounds like a weird suggestion, but this is because of what can happen to the stored password after you're done using it. A string can actually potentially remain in memory long after you've stopped using it, but a character array can be emptied out so it no longer contains data.

This all has to do with the way the garbage collectors and immutable objects work. In my opinion, the point that a hacker has access to a snapshot of your computer's memory, you probably have bigger things to worry about but still, it's always good to follow best practiceswhen you can. Anyway, if you can't prompt the user for a password for some reason, and you have to store it somewhere, the third best thing is to store it as and encrypted string. That way, you can decrypt it in your program as a character array and it won't be visible to the naked eye.

Let's say that we wanna store an encrypted password in our properties file. Step #1 is to encrypt the password string. Java has several encryption algorithms to choose from including AES, Blowfish, DES, and RSA. Different versions of Java have a different assortment of algorithms available and the java cryptography architecture allows the use of plug-ins so you can also add more algorithms if you need to. I'm going to quietly avoid a discussion of which algorithm is the best, and I'm just going to choose one for this application. AES is the top of my list so I'll use that.

Before we encrypt the string, we need to generate an AES key. A key is essentially a password, but it's in binary form and it's normally much more complex than any password you normally use. To generate a new key, we just have to do this. We use the Java Crypto KeyGenerator to get an AES instance and initialize it with the size of the key we want to generate. AES allows us to use 128, 192, or 256 bit keys. Then we ask it to generate a key.

Great! Now we have a key, but we have to store it somewhere. The standard way to store keys in Java is to use a Keystore. A Keystore is a password-protected binary file that can store multiple keys and certificates for use in situations just like this. The problem is, you still have to have a password to open a Keystore, so in some ways, you're just shifting the problem from storing a password to storing a password you used to get the password. So for the sake of example, we're gonna show you three options for generating a key in this very simple non-production app.

The first option builds a key from a known byte array. This might have been generated as a secret key previously or a sister random set of bytes. The second option gets bytes from a known password string and then copies those bytes into an array that's the correct size for our algorithm. The third option, uses a known random seed and creates a secure random object using that seed. We can then create a secret key from that using the KeyGenerator. In all of these cases, you have to store a key or a string or a seed value somewhere, so it's really hard to say that any of these options is better than any of the others.

There really is no perfect way. As I've said before, the best way is to have the user enter a password every time and then we can avoid all of this, but for now, let's just say that this is good enough and we can move on. However you do it, you need to create and store a secret key somewhere. Talk to your security folks about how best to do that. Once you have a key, you can encrypt a string like this. What we do here is, create a cipher object with the same algorithm used by the secret key, encrypt the string using the cipher and the secret key, and then Base64 and code the encrypted bytes because the encrypted string ends up being a byte array, not another string.

Even though Base64 encoding is an old and standard way to create a string representation of a byte array, the Base64 class itself is new to Java 8. If you're using an older version of Java,you'll have to use a third party implementation of Base64. There's a lot of open source and public domain versions to choose from or you can find another way to encode the bytes as a string. In any case, this gives us a string version of the encrypted string that's easy to storeinto our properties file. Lastly, here's the method that will decrypt our encrypted and Base64 encoded string.

This is the same general principle as encoding, just in reverse. First, we Base64 decode the string into a byte array. Then we create a cipher with our secret key. And then we decrypt the byte array into another byte array and convert that to a character array. You can easily convert this character array into a string. There's actually a string constructor that takes a character array as an argument. So if you really need the decrypted text as a string, you can do that pretty easily. However, like I said before, best practice is that you leave it as a character array and clear out the character array as soon as you don't need it anymore.

To test all this out, we can create a small test class to call the KeyTest method. The KeyTest method just calls bill key and then uses the key to encrypt and decrypt a string. After that, it prints the results to the console. Let's create a test class. We'll give it a main method. And we'll create a database test object and run KeyTest. I'll right click the class and run it and it shows an encrypted password at the bottom along with a decrypted version of that same password.

You can see that if we run this multiple times, we keep getting the same result. That's good.That means that we're getting the same key every time and when we encrypt and decrypt,we're always getting the same thing. So, now we know how to encrypt and decrypt a string.There really are a lot more options built into the Java Cryptography Architecture so if you wanna learn more, here are some links to the official Oracle documentation.

猜你喜欢

转载自blog.csdn.net/qq_33471057/article/details/92394405
ex2