JDBC高級
1. Statement操作SQL語句
1.1 Statement查詢SQL數據操作
@Test
public void testSelectOne ( ) {
ResultSet resultSet = null;
Statement statement = null;
Connection connection = null;
User user1 = null;
try {
Class. forName ( "com.mysql.jdbc.Driver" ) ;
String url = "jdbc:mysql://localhost:3306/nzgp2001?useSSL=true" ;
String user = "root" ;
String password = "123456" ;
connection = DriverManager. getConnection ( url, user, password) ;
String sql = "select * from nzgp2001.user where id = 1" ;
statement = connection. createStatement ( ) ;
resultSet = statement. executeQuery ( sql) ;
while ( resultSet. next ( ) ) {
int id = resultSet. getInt ( "id" ) ;
String userName = resultSet. getString ( "userName" ) ;
String password1 = resultSet. getString ( "password" ) ;
user1 = new User ( id, userName, password1) ;
System. out. println ( user1) ;
}
} catch ( ClassNotFoundException | SQLException e) {
e. printStackTrace ( ) ;
} finally {
try {
if ( resultSet != null) {
resultSet. close ( ) ;
}
if ( statement != null) {
statement. close ( ) ;
}
if ( connection != null) {
connection. close ( ) ;
}
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
}
@Test
public void testSelectAll ( ) {
ResultSet resultSet = null;
Statement statement = null;
Connection connection = null;
List< User> list = new ArrayList < > ( ) ;
try {
Class. forName ( "com.mysql.jdbc.Driver" ) ;
String url = "jdbc:mysql://localhost:3306/nzgp2001?useSSL=true" ;
String user = "root" ;
String password = "123456" ;
connection = DriverManager. getConnection ( url, user, password) ;
String sql = "select * from nzgp2001.user" ;
statement = connection. createStatement ( ) ;
resultSet = statement. executeQuery ( sql) ;
while ( resultSet. next ( ) ) {
int id = resultSet. getInt ( "id" ) ;
String userName = resultSet. getString ( "userName" ) ;
String password1 = resultSet. getString ( "password" ) ;
list. add ( new User ( id, userName, password1) ) ;
}
for ( User user1 : list) {
System. out. println ( user1) ;
}
} catch ( ClassNotFoundException | SQLException e) {
e. printStackTrace ( ) ;
} finally {
try {
if ( resultSet != null) {
resultSet. close ( ) ;
}
if ( statement != null) {
statement. close ( ) ;
}
if ( connection != null) {
connection. close ( ) ;
}
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
}
2. JDBC工具類封裝
需要完成的內容
1. 數據庫連接對象java.sql.Connection獲取過程
2. 關閉資源
JDBC工具類
1. 所有的方法都是static修飾的靜態方法
2. 需要考慮自動加載過程,完成一些必要數據的自動處理
url
driver
user
password
3. 所需數據庫連接條件保存到文件中
4. 關閉方法提供多種多樣組合方法
【注意】
db.properties文件保存到src目錄下
# 當前JDBC連接所需的驅動
driverClass=com.mysql.jdbc.Driver
# 數據庫連接符合JDBC規範的url
url=jdbc:mysql://localhost:3306/nzgp2001?useSSL=true
# 用戶名
user=root
# 密碼
password=123456
package util;
import java. io. FileInputStream;
import java. io. IOException;
import java. sql. *;
import java. util. Properties;
public class JdbcUtil {
private static String url = null;
private static String user = null;
private static String password = null;
static {
try {
Properties properties = new Properties ( ) ;
properties. load ( new FileInputStream ( "./src/db.properties" ) ) ;
String driverClass = properties. getProperty ( "driverClass" ) ;
url = properties. getProperty ( "url" ) ;
user = properties. getProperty ( "user" ) ;
password = properties. getProperty ( "password" ) ;
Class. forName ( driverClass) ;
} catch ( IOException | ClassNotFoundException e) {
e. printStackTrace ( ) ;
}
}
public static Connection getConnection ( ) {
Connection connection = null;
try {
connection = DriverManager. getConnection ( url, user, password) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
return connection;
}
public static void close ( Connection connection) {
close ( connection, null, null) ;
}
public static void close ( Connection connection, Statement statement) {
close ( connection, statement, null) ;
}
public static void close ( Connection connection, Statement statement, ResultSet resultSet) {
try {
if ( resultSet != null) {
resultSet. close ( ) ;
}
if ( statement != null) {
statement. close ( ) ;
}
if ( connection != null) {
connection. close ( ) ;
}
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
}
3. PreparedStatement使用
3.1 PreparedStatement插入數據SQL完成
@Test
public void testInsert ( ) {
User user = new User ( 10 , "逗比匿名君" , "123456" ) ;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtil. getConnection ( ) ;
String sql = "insert into nzgp2001.user(id, userName, password) VALUE (?,?,?)" ;
preparedStatement = connection. prepareStatement ( sql) ;
preparedStatement. setObject ( 1 , user. getId ( ) ) ;
preparedStatement. setObject ( 2 , user. getUserName ( ) ) ;
preparedStatement. setObject ( 3 , user. getPassword ( ) ) ;
int affectedRows = preparedStatement. executeUpdate ( ) ;
System. out. println ( "affectedRows:" + affectedRows) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
} finally {
JdbcUtil. close ( connection, preparedStatement) ;
}
}
3.2 PreparedStatment修改SQL完成
@Test
public void testUpdate ( ) {
User user = new User ( 10 , "逗比匿名君" , "航海中路彭于晏" ) ;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtil. getConnection ( ) ;
String sql = "update user set userName = ?, password = ? where id = ?" ;
preparedStatement = connection. prepareStatement ( sql) ;
preparedStatement. setObject ( 1 , user. getUserName ( ) ) ;
preparedStatement. setObject ( 2 , user. getPassword ( ) ) ;
preparedStatement. setObject ( 3 , user. getId ( ) ) ;
int affectedRows = preparedStatement. executeUpdate ( ) ;
System. out. println ( "affectedRows:" + affectedRows) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
} finally {
JdbcUtil. close ( connection, preparedStatement) ;
}
}
3.3 PreparedStatment刪除SQL完成
@Test
public void testDelete ( ) {
int id = 7 ;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtil. getConnection ( ) ;
String sql = "delete from user where id = ?" ;
preparedStatement = connection. prepareStatement ( sql) ;
preparedStatement. setObject ( 1 , id) ;
int affectedRows = preparedStatement. executeUpdate ( ) ;
System. out. println ( "affectedRows:" + affectedRows) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
} finally {
JdbcUtil. close ( connection, preparedStatement) ;
}
}
3.4 PreparedStatment查詢SQL完成
@Test
public void testSelectOne ( ) {
int id = 10 ;
User user = null;
ResultSet resultSet = null;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtil. getConnection ( ) ;
String sql = "select * from user where id = ?" ;
preparedStatement = connection. prepareStatement ( sql) ;
preparedStatement. setObject ( 1 , id) ;
resultSet = preparedStatement. executeQuery ( ) ;
if ( resultSet. next ( ) ) {
String userName = resultSet. getString ( "userName" ) ;
String password = resultSet. getString ( "password" ) ;
user = new User ( id, userName, password) ;
}
if ( user != null) {
System. out. println ( user) ;
}
} catch ( SQLException e) {
e. printStackTrace ( ) ;
} finally {
JdbcUtil. close ( connection, preparedStatement, resultSet) ;
}
}
@Test
public void testSelectAll ( ) {
List< User> list = new ArrayList < > ( ) ;
ResultSet resultSet = null;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtil. getConnection ( ) ;
String sql = "select * from user" ;
preparedStatement = connection. prepareStatement ( sql) ;
resultSet = preparedStatement. executeQuery ( ) ;
while ( resultSet. next ( ) ) {
int id = resultSet. getInt ( "id" ) ;
String userName = resultSet. getString ( "userName" ) ;
String password = resultSet. getString ( "password" ) ;
list. add ( new User ( id, userName, password) ) ;
}
for ( User user : list) {
System. out. println ( user) ;
}
} catch ( SQLException e) {
e. printStackTrace ( ) ;
} finally {
JdbcUtil. close ( connection, preparedStatement, resultSet) ;
}
}
4. SQL注入問題
Statement是一個SQL語句搬運工對象,不存在SQL語句語預處理能力,Java代碼SQL語句原封不動搬運到數據庫!!!
PreparedStatement 存在SQL語句預處理過程,這個過程可以有效的防止一定條件的SQL注入
Statement存在SQL注入問題,而PreparedStatemen可以有效的避免SQL注入
牆裂推薦使用PreparedStatement
1. PreparedStatement操作性更強
2. PreparedStatement安全性更高
package com. qfedu. a_statement;
import util. JdbcUtil;
import java. sql. *;
public class Demo1 {
private static String userName = "逗比匿名君" ;
private static String password = "fdafdsafdsa' or 1=1 -- " ;
public static void main ( String[ ] args) {
statementSelect ( ) ;
preparedStatementSelect ( ) ;
}
public static void statementSelect ( ) {
ResultSet resultSet = null;
Statement statement = null;
Connection connection = null;
try {
connection = JdbcUtil. getConnection ( ) ;
statement = connection. createStatement ( ) ;
String sql = "select * from user where userName = '" + userName + "' and password = '" + password + "'" ;
resultSet = statement. executeQuery ( sql) ;
if ( resultSet. next ( ) ) {
System. out. println ( "Statement 登陸成功" ) ;
} else {
System. out. println ( "Statement 登陸失敗" ) ;
}
} catch ( SQLException e) {
e. printStackTrace ( ) ;
} finally {
JdbcUtil. close ( connection, statement, resultSet) ;
}
}
public static void preparedStatementSelect ( ) {
ResultSet resultSet = null;
PreparedStatement preparedStatement = null;
Connection connection = null;
try {
connection = JdbcUtil. getConnection ( ) ;
String sql = "select * from user where userName = ? and password = ?" ;
preparedStatement = connection. prepareStatement ( sql) ;
preparedStatement. setObject ( 1 , userName) ;
preparedStatement. setObject ( 2 , password) ;
resultSet = preparedStatement. executeQuery ( ) ;
if ( resultSet. next ( ) ) {
System. out. println ( "PreparedStatement 登陸成功" ) ;
} else {
System. out. println ( "PreparedStatement 登陸失敗" ) ;
}
} catch ( SQLException e) {
e. printStackTrace ( ) ;
} finally {
JdbcUtil. close ( connection, preparedStatement, resultSet) ;
}
}
}
5. BaseDao封裝
5.1 需求和問題
需求
1. 完成通用的更新方法,滿足insert,update,delete操作
2. 完成通用的查詢方法,滿足select
問題
1. 數據庫連接對象獲取[解決]
2. 資源關閉[解決]
3. PreparedStatement參數賦值過程【未解決】
a. 參數個數
PreparedStatement預處理SQL語句?有多少個
b. 賦值順序‘
參數傳入方式和順序問題
4. 查詢結果集解析過程【未解決】
a. 返回值是一個List<目標數據類型>集合
b. 返回值是一個Object數組
5.2 【補充知識點-元數據】
三種元數據
數據庫元數據
通過java.sql.Connection獲取對應的元數據
SQL語句元數據
通過java.sql.PreparedStatement獲取對應的元數據
數據庫結果集元數據
通過java.sql.ResultSet獲取對應的元數據
MetaData
【重點】
1. SQL語句元數據,參數元數據其中的參數個數 對應 ? 佔位符個數
2. 結果集元數據中的字段個數,和對應當前字段下標的字段名字
package com. qfedu. b_matedata;
import org. junit. Test;
import util. JdbcUtil;
import java. sql. *;
public class TestMetaData {
@Test
public void databaseMetaData ( ) throws SQLException {
Connection connection = JdbcUtil. getConnection ( ) ;
DatabaseMetaData metaData = connection. getMetaData ( ) ;
System. out. println ( "UserName:" + metaData. getUserName ( ) ) ;
System. out. println ( "DriverVersion:" + metaData. getDriverVersion ( ) ) ;
System. out. println ( "DriverName:" + metaData. getDriverName ( ) ) ;
System. out. println ( "URL:" + metaData. getURL ( ) ) ;
System. out. println ( connection) ;
}
@Test
public void sqlMetaData ( ) throws SQLException {
Connection connection = JdbcUtil. getConnection ( ) ;
String sql = "insert into nzgp2001.user(id, userName, password) VALUE (?,?,?)" ;
PreparedStatement preparedStatement = connection. prepareStatement ( sql) ;
ParameterMetaData parameterMetaData = preparedStatement. getParameterMetaData ( ) ;
System. out. println ( "當前SQL語句的參數個數:" + parameterMetaData. getParameterCount ( ) ) ;
JdbcUtil. close ( connection, preparedStatement) ;
}
@Test
public void resultMetaData ( ) throws SQLException {
Connection connection = JdbcUtil. getConnection ( ) ;
String sql = "select * from user" ;
PreparedStatement preparedStatement = connection. prepareStatement ( sql) ;
ResultSet resultSet = preparedStatement. executeQuery ( ) ;
ResultSetMetaData metaData = resultSet. getMetaData ( ) ;
int columnCount = metaData. getColumnCount ( ) ;
while ( resultSet. next ( ) ) {
for ( int i = 1 ; i <= columnCount; i++ ) {
String columnName = metaData. getColumnName ( i) ;
System. out. println ( columnName + ":" + resultSet. getObject ( columnName) ) ;
}
}
JdbcUtil. close ( connection, preparedStatement, resultSet) ;
}
}
5.3 【補充知識點 BeanUtils使用】
BeanUtils提供了對於符合JavaBean規範的實體類進行賦值,取值,拷貝操作的一系列方法,可以自動完成數據類型轉換,方便開發者在數據交互中使用。
所有的方法都是靜態方法
三個方法
1. 賦值指定成員變量對應數據
a. 符合JavaBean規範的類對象
b. 指定成員變量的名字
c. Object類型數據用於賦值成員變量
2. 取值指定成員變量的數據
a. 符合JavaBean規範的類對象
b. 指定成員變量的名字
返回值是對應當前成員變量的數據類型
3. 拷貝符合JavaBean規範的兩個對象數據
a. 符合JavaBean規範的目標類對象
b. 符合JavaBean規範的目標數據源對象
4. 真香方法,從Map雙邊對聯中匹配賦值數據到符合JavaBean規範的類對象
a. 符合JavaBean規範的類對象
b. Map雙邊隊列
package com. qfedu. c_testbeanutils;
import com. qfedu. a_statement. User;
import org. apache. commons. beanutils. BeanUtils;
import org. junit. Test;
import java. lang. reflect. InvocationTargetException;
import java. util. HashMap;
public class Demo1 {
@Test
public void testSetProperty ( )
throws InvocationTargetException, IllegalAccessException {
User user = new User ( ) ;
BeanUtils. setProperty ( user, "id" , "123" ) ;
BeanUtils. setProperty ( user, "userName" , "騷磊" ) ;
BeanUtils. setProperty ( user, "password" , 123456 ) ;
System. out. println ( user) ;
}
@Test
public void testGetProperty ( )
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
User user = new User ( 1 , "騷磊" , "2344567" ) ;
System. out. println ( BeanUtils. getProperty ( user, "id" ) ) ;
System. out. println ( BeanUtils. getProperty ( user, "userName" ) ) ;
System. out. println ( BeanUtils. getProperty ( user, "password" ) ) ;
}
@Test
public void testCopyProperties ( ) throws InvocationTargetException, IllegalAccessException {
User user = new User ( 1 , "騷磊" , "2344567" ) ;
User user1 = new User ( ) ;
System. out. println ( "before:" + user1) ;
BeanUtils. copyProperties ( user1, user) ;
System. out. println ( "after:" + user1) ;
}
@Test
public void 真香( ) throws InvocationTargetException, IllegalAccessException {
HashMap< String, Integer> map = new HashMap < > ( ) ;
map. put ( "userName" , 100 ) ;
map. put ( "location:" , 1 ) ;
map. put ( "password" , 1111 ) ;
map. put ( "id" , 2 ) ;
User user = new User ( ) ;
System. out. println ( "before:" + user) ;
BeanUtils. populate ( user, map) ;
System. out. println ( "after:" + user) ;
}
}
5.4 通用更新方法實現
分析:
完成通用的更新方法,update,insert,delete操作
權限修飾符:
public
返回值類型:
int 當前SQL語句參數,數據庫收到影響的行數
方法名:
update
形式參數列表:
1. String sql語句
指定執行的SQL語句 update insert delete。。。
2. SQL語句可能需要參數
SQL有可能沒有參數,有可能多個參數,而且參數類型都不一樣!!!
a. Object...
Object類型的不定長參數
b. Object[]
所有對應當前SQL語句的參數都存儲在Object類型數組中
(String sql, Object[] parameters)
方法聲明:
public int update(String sql, Object[] parameters)
public int update ( String sql, Object[ ] parameters) {
int affectedRows = 0 ;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtil. getConnection ( ) ;
preparedStatement = connection. prepareStatement ( sql) ;
int parameterCount = preparedStatement. getParameterMetaData ( ) . getParameterCount ( ) ;
if ( parameterCount != 0 && parameters != null && parameterCount == parameters. length) {
for ( int i = 0 ; i < parameters. length; i++ ) {
preparedStatement. setObject ( i + 1 , parameters[ i] ) ;
}
}
affectedRows = preparedStatement. executeUpdate ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
} finally {
JdbcUtil. close ( connection, preparedStatement) ;
}
return affectedRows;
}
5.5 通用查詢方法實現
分析:
完成通用的查詢方法,select操作
權限修飾符:
public
需要聲明泛型
T ==> Type
返回值類型:
List<指定數據類型>
方法名:
query
形式參數列表:
1. String sql語句
指定執行的SQL語句 Select語句
2. SQL語句可能需要參數
SQL有可能沒有參數,有可能多個參數,而且參數類型都不一樣!!!
a. Object...
Object類型的不定長參數
b. Object[]
所有對應當前SQL語句的參數都存儲在Object類型數組中
3. 告知當前SQL語句出現的查詢結果對應數據類型是哪一個
Class<T> cls
a. 泛型T
用於數據類型約束,傳入哪一個類的.class當前T對應的就是哪一個類
b. Class 反射對應的Class類對象
爲所欲爲!!!
有了對應類的.class字節碼文件對應Class對象。可以通過反射爲所欲
爲
(String sql, Object[] parameters, Class<T> cls)
方法聲明:
public <T> List<T> query(String sql, Object[] parameters, Class<T> cls)
public < T> List< T> query ( String sql, Object[ ] parameters, Class< T> cls) {
ResultSet resultSet = null;
Connection connection = null;
PreparedStatement preparedStatement = null;
List< T> list = new ArrayList < > ( ) ;
try {
connection = JdbcUtil. getConnection ( ) ;
preparedStatement = connection. prepareStatement ( sql) ;
int parameterCount = preparedStatement. getParameterMetaData ( ) . getParameterCount ( ) ;
if ( parameterCount != 0 && parameters != null && parameterCount == parameters. length
for ( int i = 0 ; i < parameters. length; i++ ) {
preparedStatement. setObject ( i + 1 , parameters[ i] ) ;
}
}
resultSet = preparedStatement. executeQuery ( ) ;
ResultSetMetaData metaData = resultSet. getMetaData ( ) ;
int columnCount = metaData. getColumnCount ( ) ;
while ( resultSet. next ( ) ) {
T t = cls. getConstructor ( ) . newInstance ( ) ;
for ( int i = 1 ; i <= columnCount; i++ ) {
String fieldName = metaData. getColumnName ( i) ;
Object value = resultSet. getObject ( fieldName) ;
BeanUtils. setProperty ( t, fieldName, value) ;
}
list. add ( t) ;
}
} catch ( SQLException | NoSuchMethodException | InstantiationException
| IllegalAccessException | InvocationTargetException e) {
e. printStackTrace ( ) ;
} finally {
JdbcUtil. close ( connection, preparedStatement, resultSet) ;
}
return list. size ( ) != 0 ? list : null;
}