5.1 JDBC API

1. JDBC (Java Database Connectivity) is an API for interacting with a database in Java.

2. Each database vendor produces a driver that translates JDBC requests to the database-specific protocol.

3. JDBC is based on SQL (Standard Query Lanauge) for database access.

4. JDBC provides classes for issuing SQL statements and for working with the query results.

5. Object-relational mappers provide a higher-level mechanism (Hibernate or JPA) for working with a database, but you should understand SQL/JDBC to use them effectively.


5.2 Requirements for Using JDBC

1. You need a database, we use Mysql as example

About how to install Mysql, you can refer to https://www.cnblogs.com/bruce-he/p/10454856.html, it is similar in Windows.

2. You need a database driver JAR, such as mysql-connector-j-8.0.32.jar for Mysql

Without using Spring MVC or Spring Boot framework, you can follow below steps to add it in IdeaJ.

1. Vist https://mvnrepository.com/, then type "mysql-connector-java" to search
2. In the first "MySQL Connector/J" item, download the latest JDBC driver. Choose "jar" Files to download.
3. In the IdeaJ, follow the detailed step in the picture below.

3. Config the database connection properties.

jdbc.drivers=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/javatest?userUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root

4. Use this code to establish a JDBC connection:

// use Properties to parse jdbc.properties
var props = new Properties();
try (InputStream in = Files.newInputStream(Paths.get("./v2ch05/src/database.properties"))) {
props.load(in);
}
String drivers = props.getProperty("jdbc.drivers");
if (drivers != null) {
System.setProperty("jdbc.drivers", drivers);
}
String url = props.getProperty("jdbc.url");
String username = props.getProperty("jdbc.username");
String password = props.getProperty("jdbc.password"); Connection conn = DriverManager.getConnection(url, username, password);
return conn;

5. You use the Connection object to create SQL statement

try (Connection conn = getConnection();
// Statement 是 Java 执行数据库操作的一个重要接口,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。Statement对象,用于执行不带参数的简单SQL语句。
Statement stat = conn.createStatement()) {
stat.executeUpdate("CREATE TABLE Greetings (Message CHAR(20))");
}

6. Database connections are a limited resource. When you are done, be sure to close the connection.


5.4 Executing SQL Statements

5.4.1 Executing SQL

1. To execute a SQL statement, create a Statement object:

Statement stat = conn.createStatement();

2. To update the database (INSERT, UPDATE, DELETE), call the executeUpdate method, and the number of affected rows is returned.

String command = "UPDATE Books SET Price = Price - 5.00 WHERE Title NOT LIKE '%Introduction%'";
int rows = stat.executeUpdate(command);

3. Use executeQuery to issue a SELECT query, and an ResultSet type object is returned.

ResultSet result = stat.executeQuery("SELECT * FROM Books");

4. Use execute to issue arbitrary SQL commands.

5.4.2 Managing JDBC objects

1. A connection object can produce one or more Statement objects.

  • Some database drivers only allow one Statement at a time.
  • Call DatabaseMetaData.getMaxStatements to find out.

2. You can use the same Statement object for multiple queries.

3. A Statement can have at most one open ResultSet.

  • Don't work with multiple result sets at a time. Issue a query that gives you all data in one result set.

4. When you execute another query or close a Statement, an open result set is closed.

  • The Statement.closeOnComplete method closes the statement as soon as an open result set is closed.
  • Some other person, put the each Connection, Statement and ResultSet in try-with-resources.

5. When you close a Connection, all statements are closed.

5.4.3 SQLExceptions and Warnings

1. A SQLException has a chain of SQLException objects. This is in addition to the "cause" chain that all exceptions have.

2. The  SQLException class extends the Iterable<Throwable> interface, you can iterate over all exceptions like this:

for (Throwable t : sqlException) {
do something with t
}

3. The SQLException.getSQLState method yields a string that is standardized by either X/Open or SQL:2003.

  • Call DatabaseMetaData.getSQLStateType to find out which standard is used by your driver.

4. There is also a chain of warnings:

SQLWarning w = stat.getWarning();
while (w != null) {
do something with w
w = w.nextWarning(); // it's different from SQLException, each warning has a nextWarning() method
}

5.4.4 Result Sets

1. A query yields a ResultSet:

ResultSet rs = stat.exectQuery("SELECT * FROM Books");

2. Use this loop to iterate over the rows:

while (rs.next()) {
look at a row of the result set
}

3. To get at the columns of a row, use one of the get methods:

String isbn = rs.getString(1);  // The first(!) column, to get the value using column index
double price = rs.getDouble("Price"); // to get the value using column name

5.5 Executing Query Operation

5.5.1 Prepared Statements

1. When a query has variable parts, you don't want to formulate it through string concatenation:

String query = "SELECT * FROM Books WHERE Books.Title = ; + title;    // Don't - or you may become the victim of SQL injection

2. Instead, use a prepared statement:

String query = "SELECT * FROM Books WHERE Books.Title = ?";
PreparedStatement stat = conn.preparedStatement(query);
stat.setString(1, title); // 1) setString() for String, setInt() for Integer, SetDouble() for Double; 2) first index is 1
ResultSet rs = stat.executeQuery();

3. A preparedStatement becomes invalid after closing the Connection that created it. But the database will cache the query plan.

5.5.3 SQL Escapes

1. The "escape" syntax supports features for which database syntax varies.

2. Specify date and time literals as:

{d '2008-01-24'}
{t '23:59:59'}
{ts '2008-01-24 23:59:59.999' }

3. To call a scalar function (that is , a function returning a single value), embed the standard function name and argument like this:

{fn left(?, 20)}
{fn user()}

4. Here is how to call a stored procedure:

{call PROC1(?, ?)}
{call PROC2}
{? = call PROC3(?)}

5. The {oj ...} escape lets you fomulate outer joins in a database-independent way.

6. You can specifiy an escape character, for example, to match all titles containg a literal %

... WHERE ? like %!_% {escape '!'}    // ! 为转义字符, !_ 表示字面常量下划线,如查找 "javacore_chapter1"

5.5.4 Multiple Results

1. It is possible for a query to return multiple result sets or update counts.

  • This can happen with stored procedures.
  • Some databases allow you to submit multiple SELECT statements together.

2. Use the following loop to analyze the query result:

boolean isResult = stat.execute(command);
boolean done = false;
while (!done) {
if (isResult) {
ResultSet result = stat.getResultSet();
do something with result
}
else {
int updateCount = stat.getUpdateCount();
if (updateCount >= 0) {
do something with updateCount
}
else {
done = true;
}
}
if (!done) {
isResult = stat.getMoreResults();
}
}

获取所有结果集的步骤:

  • 1. 使用 execute() 执行 SQL 语句;
  • 2. 获取第一个结果集或更新计数;
  • 3. 重复调用 getMoreResults() 以移动到下一个结果集;
  • 4. 当不存在更多的结果集或更新计数时,完成操作

5.5.5 Retrieving Autogenerated Values

1. Most databases support some mechanism for automatcally generating values.

  • MySQL: Id INTEGER AUTO_INCREMENT
  • Derby: Id INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1)

2. You can retrieve the autogenerated values that were generated by an INSERT statement:

stat.executeUpdate(insertStatement, Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stat.getGeneratedKeys();
if (rs.next()) {
int key = rs.getInt(1);
Do something with key
}

5.6 Scrollable Result Sets

1. The ResultSet.next() iterates over the rows of a result set.

2. A scrollable result set allows you to move the current row by arbitrary amounts and to arbitrary positions.

3. A scrollable result set can be updatable: you can set the column values, and the changes are reflected in the database.

4. Construct a scrollable or updatable result set like this:

Statement stat = conn.createStatement(type, concurrency);

PreparedStatement stat = conn.preparedStatement(command, type, concurrency);

5. To scroll within the result set, call:

rs.previous()
rs.relative(n)
rs.absolute(n)

6. The getCurrentRow() yields the current row number (starting at 1) or 0 if the cursor is before the first or after the last row.

7. If the result set is updatable, call one of the update() to change a column value:

double price = rs.getDouble("Price");
rs.updateDouble("Price", price + increase);
rs.updateRow(); // call updateRow() to store the changes in database

8. To insert a new row, call

rs.moveToInsertRow();
call rs.updateXxx(...)
rs.insertRow();
rs.moveToCurrentRow();

9. The ResultSet.deleteRow() removes the row from the result set and the database.

10. Update result sets are intended for table editing by end users. If you want to update the database programmatically, use SQL queries.


5.7 Row Sets

5.7.2 Cached Row Sets

1. Updatable result sets require a connection to the database, while connections are scarce resources.

2. A cached row set is like an updatable result set, but it can be disconnected from the database.

3. Obtain a cached row set like this:

RowSetFactory factory = RowSetFactory.newFactory();
CachedRowSet crs = factory.createCachedRowSet();

4. Then populate it with a result set:

ResultSet result = ...;
crs.populate(result);
conn.close(); // now OK to close the database connection

5. Now you can view and update the row set. When you are done, call crs.acceptChanges(conn), passing a new Connection object.

6. Alternatively, you can let the cached row set establish a connection automatically as needed. First, set up the connection parameters:

crs.setURL("jdbc:mysql://127.0.0.1:3308/javatest)
crs.setUsername("root");
crs.setPassword("root");

7. Then set the query statement and any parameters, and execute the query:

crs.setCommand("SELECT * FROM Books WHERE Title = ?");
crs.setString(1, title);
crs.execute();

8. When you are done updating the row set, you can call crs.acceptChanges() without a Connection parameter.


5.8 Metadata

1. Metadata are data that describe the database or its parts.

2. First, get a DatabaseMetaData object from a connection:

DatabaseMetaData meta = conn.getMetaData();

3. This call yields a result set that lists all tables in the database:

ResultSet mrs = meta.getTables(null, null, null, new String[] {"TABLE"});

4. As it happens, the third column is the table name:

while (mrs.next()) {
System.out.println(mrs.getString(3));
}

5. There are many methods to disclose how the database driver behave under conditions that are not standardized, such as:

meta.supportsCatalogsInPrivilegeDefinitions()
meta.nullPlusNonNullIsNull()

Result Set Metadata

1. The ResultSetMetaData interface has methods to describe a result set.

2. This is particularly useful for generic tools that work with arbitrary tables.

3. Here we find out column sizes and column labels, useful information for displaying a result:

ResultSet rs = stat.executeQuery("SELECT * FROM " + tableName);
ResultSetMetaData meta = rs.getMetaData();
for (int i = 1; i <= meta.getColumnCount(); i++) {
String columnName = meta.getColumnLabel(i);
String columnWidth = meta.getColumnDisplaySize(i);
...
}

5.9 Transactions

5.9.1 Transactions

1. You can group a set of statements to form a transaction. When all has gone well, the transaction is committed, If something goes wrong, the transaction is rolled back, as if none of its statement has been issued.

2. By default, a connection is in "autocommit" mode: Each statement is committed as it is executed.

3. In order to use tansaction, first turn off autocommit, then execute any number of statements and commit your work.

conn.setAutoCommit(false);
Statement stat = conn.createStatement();
stat.executeUpdate(command1);
stat.executeUpdate(command2);
...
conn.commit();

4. However, if an error occurred, call:

conn.rollback();

5.9.3 Batch Updates

1. Suppose an application populates a database with many INSERT statements. You can improve performance with a batch update instead of calling executeUpdate, call the addBatch method:

String command = "CREATE TABLE ...";
stat.addBatch(command);
while (...) {
command = "INSERT INTO ... VALUES(" + ... + ")";
stat.addBatch(command);
}

2. Finally, submit the entire batch:

int counts = stat.executeBatch();    // Yields row counts for all submitted statements

最新文章

  1. Java关于Properties用法(二)——替换配置文件中的参数
  2. OPENQUERY 无行返回 无数据返回 数据缺失
  3. json 数据 添加 删除 排序
  4. spark单机环境下运行一些解决问题
  5. Tooltip jqueryui
  6. mongodb聚合内存不足解决方案
  7. data属性
  8. C#局域网桌面共享软件制作(一)
  9. js判断是移动端还是pc端
  10. Codeforces 447 C DZY Loves Sequences【DP】
  11. ubuntu12.10设置禁止锁屏和屏幕常亮
  12. 虚拟内存设备驱动memdev及实例代码
  13. Android_Studio 及SDK下载
  14. CodeForces#378--A, B , D--暴力出奇迹....
  15. 使用spark-streaming实时读取Kafka数据统计结果存入MySQL
  16. Debug Dump file
  17. webpack学习笔记——publicPath路径问题
  18. 七月在线爬虫班学习笔记(二)——Python基本语法及面向对象
  19. 64位Ubuntu系统下ROP攻击
  20. HTML的简介

热门文章

  1. LG P3653 小清新数学题
  2. JZOJ 3184. 【GDOI2013模拟7】最大异或和
  3. Vulhub 漏洞学习之:Adobe ColdFusion
  4. JSP 与 Servlet 之间的联系,及其语法
  5. windows pwn(一)
  6. html(Angular) 调用本地安装exe程序
  7. dotnet core 托管
  8. LeetCode-798 得分最高的最小论调 及差分和前缀和的学习
  9. OpenAI Java SDK——chatgpt-java-v1.0.3更新支持GPT-3.5-Turbo,支持语音转文字,语音翻译。
  10. 【转载】docker swarm集群中部署traefik和其他服务