1. Statement操作SQL语句
1.1 Statement查询SQL数据操作
// 查询指定的一个数据行,转换成对应的User对象
@Test
public void testSelectOne() {ResultSet resultSet = null;Statement statement = null;Connection connection = null;User user1 = null;try {// 1. 加载驱动Class.forName("com.mysql.jdbc.Driver");// 2. 准备必要的连接数据String url = "jdbc:mysql://localhost:3306/nzgp2001?useSSL=true";String user = "root";String password = "123456";// 3. 获取数据库连接connection = DriverManager.getConnection(url, user, password);// 4. 准备SQL语句String sql = "select * from nzgp2001.user where id = 1";// 5. 获取Statement对象statement = connection.createStatement();// 6. 执行SQL语句resultSet = statement.executeQuery(sql);// 7. ResultSet结果集对象解析过程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 {// 7. 关闭资源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;// 准备了一个存储User对象的List集合List<User> list = new ArrayList<>();try {// 1. 加载驱动Class.forName("com.mysql.jdbc.Driver");// 2. 准备必要的连接数据String url = "jdbc:mysql://localhost:3306/nzgp2001?useSSL=true";String user = "root";String password = "123456";// 3. 获取数据库连接connection = DriverManager.getConnection(url, user, password);// 4. 准备SQL语句String sql = "select * from nzgp2001.user";// 5. 获取Statement对象statement = connection.createStatement();// 6. 执行SQL语句resultSet = statement.executeQuery(sql);// 7. ResultSet结果集对象解析过程while (resultSet.next()) {// 通过指定的字段获取对应的数据int id = resultSet.getInt("id");String userName = resultSet.getString("userName");String password1 = resultSet.getString("password");// 从数据库中读取的User数据保存到对象中,添加到List内list.add(new User(id, userName, password1));}for (User user1 : list) {System.out.println(user1);}} catch (ClassNotFoundException | SQLException e) {e.printStackTrace();} finally {// 7. 关闭资源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. 需要考虑自动加载过程,完成一些必要数据的自动处理urldriveruserpassword3. 所需数据库连接条件保存到文件中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;
/*** JDBC工具类,负责数据库连接对象和数据库资源关闭** @author Anonymous 2020/3/24 10:08*/
public class JdbcUtil {// 静态成员变量,保存一些必要的数据private static String url = null;private static String user = null;private static String password = null;
// 利用static修饰的静态代码块完成文件字段自动读取和驱动自动加载过分static {try {// Properties实现类,里面的数据保存形式都是键值对形式Properties properties = new Properties();
// 使用字节输入流,加载对应db.properties,数据保存到Properties对象中properties.load(new FileInputStream("./src/db.properties"));
// 从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();}}
/*** 返回数据库连接对象,连接失败返回null** @return java.sql.Connection 数据库连接对象*/public static Connection getConnection() {Connection connection = null;
try {// 通过DriverManager驱动管理类,使用必要参数获取数据库连接connection = DriverManager.getConnection(url, user, password);} catch (SQLException e) {e.printStackTrace();}
return connection;}
/*以下三个方法实际上都是执行同一个方法,使用这种方式1. 简化代码结构2. 规范化所有的操作*/
/*** 处理数据库操作对应的资源问题** @param connection java.sql.Connection 数据库连接对象*/public static void close(Connection connection) {close(connection, null, null);}
/*** 处理数据库操作对应的资源问题** @param connection java.sql.Connection 数据库连接对象* @param statement java.sql.Statement 数据库SQL语句搬运工对象*/public static void close(Connection connection, Statement statement) {close(connection, statement, null);}
/*** 处理数据库操作对应的资源问题** @param connection java.sql.Connection 数据库连接对象* @param statement java.sql.Statement 数据库SQL语句搬运工对象* @param resultSet java.sql.ResultSet 数据库查询结果集对象*/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();// 准备SQL语句// ? 表示SQL语句参数占位符!!!String sql = "insert into nzgp2001.user(id, userName, password) VALUE (?,?,?)";// 预处理SQL语句,获取PreparedStatement对象preparedStatement = connection.prepareStatement(sql);// SQL语句赋值操作,SQL语句参数是从1开始preparedStatement.setObject(1, user.getId());preparedStatement.setObject(2, user.getUserName());preparedStatement.setObject(3, user.getPassword());// 使用PreparedStatement执行SQL语句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);// 赋值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注入
墙裂推荐使用PreparedStatement1. PreparedStatement操作性更强2. PreparedStatement安全性更高
import util.JdbcUtil;
import java.sql.*;
/*** 使用Statement和PreparedStatement完成Select操作** @author Anonymous 2020/3/24 11:07*/
public class Demo1 {private static String userName = "逗比匿名君";private static String password = "fdafdsafdsa' or 1=1 -- ";
public static void main(String[] args) {/*Statement是一个SQL语句搬运工对象,不存在SQL语句语预处理能力,Java代码SQL语句原封不动搬运到数据库!!!PreparedStatement 存在SQL语句预处理过程,这个过程可以有效的防止一定条件的SQL注入*/statementSelect();preparedStatementSelect();}
public static void statementSelect() {ResultSet resultSet = null;Statement statement = null;Connection connection = null;
try {connection = JdbcUtil.getConnection();statement = connection.createStatement();
// SQL语句准备String sql = "select * from user where userName = '" + userName + "' and password = '" + password + "'";/*select * from user where userName = '逗比匿名君' and password = 'fdafdsafdsa' or 1=1 -- '*/
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. 结果集元数据中的字段个数,和对应当前字段下标的字段名字
import org.junit.Test;
import util.JdbcUtil;
import java.sql.*;
/*** 元数据测试** @author Anonymous 2020/3/24 14:39*/
public class TestMetaData {// 数据库元数据演示@Testpublic 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);}
@Testpublic void sqlMetaData() throws SQLException {// 获取数据库连接Connection connection = JdbcUtil.getConnection();
// 准备SQL语句// ? 表示SQL语句参数占位符!!!String sql = "insert into nzgp2001.user(id, userName, password) VALUE (?,?,?)";
// 预处理SQL语句,获取PreparedStatement对象PreparedStatement preparedStatement = connection.prepareStatement(sql);
ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData();
// [重点]System.out.println("当前SQL语句的参数个数:" + parameterMetaData.getParameterCount());JdbcUtil.close(connection, preparedStatement);}
@Testpublic void resultMetaData() throws SQLException {// 获取数据库连接Connection connection = JdbcUtil.getConnection();
// 准备SQL语句// ? 表示SQL语句参数占位符!!!String sql = "select * from user";
// 预处理SQL语句,获取PreparedStatement对象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双边队列
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;
/*** BeanUtils测试** @author Anonymous 2020/3/24 15:09*/
public class Demo1 {@Testpublic void testSetProperty()throws InvocationTargetException, IllegalAccessException {User user = new User();
// 给符合JavaBean规范的指定成员变量赋值操作BeanUtils.setProperty(user, "id", "123");BeanUtils.setProperty(user, "userName", "骚磊");BeanUtils.setProperty(user, "password", 123456);
System.out.println(user);}
@Testpublic 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"));}
@Testpublic 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);}
// populate@Testpublic 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)/*** 通用的更新方法,需要参数是SQL语句和对应当前SQL语句的Object类型参数数组** @param sql String类型的SQL语句,需要执行的方法* @param parameters 对应当前SQL语句的参数列表。Object类型数组* @return SQL语句执行数据库受到影响的行数*/
public int update(String sql, Object[] parameters) {int affectedRows = 0;Connection connection = null;PreparedStatement preparedStatement = null;try {connection = JdbcUtil.getConnection();preparedStatement = connection.prepareStatement(sql);/*获取SQL语句参数个数!!!通过SQL语句元数据获取(ParameterMetaData)*/int parameterCount = preparedStatement.getParameterMetaData().getParameterCount();/*parameterCount 参数个数不能为0parameters != null 参数数组不为null,因为存在当前方法没有参数,数组传入nullparameterCount == parameters.length 参数个数和传入的Object类型参数数容量一致*/if (parameterCount != 0 && parameters != null && parameterCount == parameters.length) {for (int i = 0; i < parameters.length; i++) {/*SQL语句参数下标从1开始数组数据下标从0开始*/preparedStatement.setObject(i + 1, parameters[i]);}}// 执行SQL语句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> clsa. 泛型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)/*** 通用的查询方法,查询cls指定数据类型,返回值是一个List集合** @param sql Select SQL语句* @param parameters 对应当前SQL语句的参数* @param cls 指定数据类型,同时提供Class对象,便于里用反射操作,约束泛型类型* @param <T> 泛型占位符* @return 指定数据类型的List集合,如果集合中不存在数据 size() == 0 返回null*/
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);/*获取SQL语句参数个数!!!通过SQL语句元数据获取(ParameterMetaData)*/int parameterCount = preparedStatement.getParameterMetaData().getParameterCount();/*parameterCount 参数个数不能为0parameters != null 参数数组不为null,因为存在当前方法没有参数,数组传入nullparameterCount == parameters.length 参数个数和传入的Object类型参数数容量一致*/if (parameterCount != 0 && parameters != null && parameterCount == parameters.lengthfor (int i = 0; i < parameters.length; i++) {/*SQL语句参数下标从1开始数组数据下标从0开始*/preparedStatement.setObject(i + 1, parameters[i]);}}// 执行SQL语句,得到结果集对象resultSet = preparedStatement.executeQuery();// 结果集元数据ResultSetMetaData metaData = resultSet.getMetaData();// 字段个数int columnCount = metaData.getColumnCount();while (resultSet.next()) {// 根据Class类型创建对象,对象的类型是T类型T t = cls.getConstructor().newInstance();for (int i = 1; i <= columnCount; i++) {// 获取字段名String fieldName = metaData.getColumnName(i);// 获取对应字段数据Object value = resultSet.getObject(fieldName);// 给符合JavaBean规范的实现类,指定成员变量fieldName,赋值valueBeanUtils.setProperty(t, fieldName, value);}list.add(t);}} catch (SQLException | NoSuchMethodException | InstantiationException| IllegalAccessException | InvocationTargetException e) {e.printStackTrace();} finally {JdbcUtil.close(connection, preparedStatement, resultSet);}// 判断结果,如果List中没有存储数据,返回nullreturn list.size() != 0 ? list : null;
}