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;
}