package com.util;
import java.lang.reflect.InvocationTargetException;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class JDBCUtils {
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.println("驱动加载失败");//写到日志文件中
}
}
private static final String url = "jdbc:mysql://175.24.163.193:3306/mysql2206?useUnicode=true&characterEncoding=UTF-8&serverTimezone=PRC";
private static final String userName = "root";
private static final String passWord = "Mypass123@";
/**
*执行 insert | update| delete语句都可以调用该方法 该方法不支持事务(将来再做支持事务的方法)
* 动态代理 ,ThreadLocal
*
*
* @param sql 传入insert | update| delete语句
* @param values 第一个参数的SQL语句中存在N个?号,则values传入?号占位符的值
* 如要执行:sql="update emp set sal=sal+?" 则第二个参数必需传递一个值(传入100) 表示所有员工的工资+100
* 如要执行:sql=" insert into emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values(?,?,?,?,?,?,?,?)"
* 则第二个参数values传入8个值 分别对应员工号到部门号 values=9999,"Jerry","CLERK",7788,"2022-08-08",199999,100000,10
*
*
* @return
*/
public static int update(String sql,Object... values)throws SQLException {
Connection connection = null;
try {
//获得连接
connection = DriverManager.getConnection(url, userName, passWord);
PreparedStatement pstmt = connection.prepareStatement(sql);
//得到可运行SQL的PreparedStatement对象
//根据values的长度(元素个数)循环调用setObject方法
if(values!=null){
for(int i=0;i<values.length;i++){
//之前是用setInt,setString等方法传入与数据库表字段匹配的java类型
//但调用setObject方法时,只要values中存在元素类型与数据库的类型匹配就可以了。
pstmt.setObject(i+1,values[i]);
}
}
return pstmt.executeUpdate();//执行SQL语句
//
}finally {
if (connection!=null){
connection.close();//一定要关闭连接
}
}
}
/**
* 此方法完成简单的多表查询,单表查询的结果集映射,将结果集每一条数据映射到该方法第二个参数所表示的JavaBean对象中
* 不适用于查询列中出现分组函数(查询结果的列名无法与第二个参数对应的javaBean属性不一致的sql)
* @param sql
* @param cls
* @param values
* @param <T>
* @return
* @throws SQLException
*/
public static <T> ArrayList<T> queryData(String sql,Class<T> cls, Object... values) throws SQLException, Exception {
ArrayList<T> resutlData = new ArrayList<>();
Connection connection = null;
try {
//获得连接
connection = DriverManager.getConnection(url, userName, passWord);
PreparedStatement pstmt = connection.prepareStatement(sql);
//得到可运行SQL的PreparedStatement对象
//根据values的长度(元素个数)循环调用setObject方法
if(values!=null){
for(int i=0;i<values.length;i++){
//之前是用setInt,setString等方法传入与数据库表字段匹配的java类型
//但调用setObject方法时,只要values中存在元素类型与数据库的类型匹配就可以了。
pstmt.setObject(i+1,values[i]);
}
}
ResultSet rs = pstmt.executeQuery();//执行SQL语句
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()){//取出每一行
//一行数据先放到一个Map对象中
Map<String,Object> rowData = new HashMap<>();
for(int i=1;i<=columnCount;i++){
String columnName = metaData.getColumnLabel(i);
String columnTypeName = metaData.getColumnTypeName(i);//获得列的数据类型
int c = metaData.getPrecision(i);
int scale = metaData.getScale(i);
System.out.println("列的数据类型:"+columnTypeName+"长度:"+c+"小数位数:"+scale);
Object columnValue = null;
if (columnTypeName.equals("INT")){
columnValue = rs.getInt(i);
}else if (columnTypeName.equals("VARCHAR")){
columnValue = rs.getString(i);
}else if (columnTypeName.equals("DATE")){
columnValue = rs.getDate(i);
}else if (columnTypeName.equals("DATETIME")){
columnValue =rs.getString(i); //rs.getTimestamp(i);
}else if (columnTypeName.startsWith("DECIMAL")){
if (scale>0) {
columnValue = rs.getDouble(i);
}else{
columnValue = rs.getInt(i);
}
}else if (columnTypeName.equals("CLOB")){
columnValue = rs.getString(i);
}else{
columnValue = rs.getObject(columnName);//根据列名取出列值
}
rowData.put(columnName,columnValue);
}
//利用反射技术将一行数据映射一个javaBaen.
T javaBean = ReflectUtil.setMapValueToBean(rowData,cls);
resutlData.add(javaBean);
}
return resutlData;
}finally {
if (connection!=null){
connection.close();//一定要关闭连接
}
}
}
//编写一个通用的查询方法,可以根据传入的SQL语句返回指定一的集合
//如: sql= select * from emp 方法返回值变成ArrayList<EmpBean>
//如: sql= select * from dept 方法返回值变成ArrayList<DeptBean>
//如: sql = "select * from emp ,dept where emp.deptno=dept.deptno " 方法返回值变成ArrayList<EmpBean>
//如: sql = select avg(sal),max(sal),min(sal),deptno from emp gorup deptno 方法返回值变成ArrayList<Map<String,Object>>
//封装的思想:把变化的部分做为方法参数传入到方法体中,方法体执行固定的程序逻辑
//分析查询比较麻烦的地方在while循环取数据的方法
//
/**
*此方法可实现任意的select语句查询,但需要传递RowMapper接口的实现类对象,实现rowMap方法
* 在rowMap方法中根据我们传递的select语句
* 自定义查询结果(将一行数据封装到JavaBean,或Object[]数组,或HashMap等) 由方法的调用者自行决定
*
* 此方法的弊端在:每调用一次该方法,第二个参数必需传递RowMapper接口的实现类对象。编程比较麻烦
*
*
*
*
* @param sql
* @param rowMapper 传入RowMapper接口的实现类, 如果实现类为class EmpRowMapper implements RowMapper<EmpBean>{},
* 则方法的返回值类型ArrayList为ArrayList<EmpBean>
* @param values
* @param <T>
* @return
* @throws SQLException
*/
//Object... values可变参数可以传递 值1,值2,值3表示我们要传递的数据,在方法内部当做数组看待的
//Object... values可变参数可以传传递Object[] 类型的数组,在方法内部将期当做数组数
public static <T> ArrayList<T> queryData(String sql,RowMapper<T> rowMapper, Object... values) throws SQLException {
ArrayList<T> resutlData = new ArrayList<>();
Connection connection = null;
try {
//获得连接
connection = DriverManager.getConnection(url, userName, passWord);
PreparedStatement pstmt = connection.prepareStatement(sql);
//得到可运行SQL的PreparedStatement对象
//根据values的长度(元素个数)循环调用setObject方法
if(values!=null){
for(int i=0;i<values.length;i++){
//之前是用setInt,setString等方法传入与数据库表字段匹配的java类型
//但调用setObject方法时,只要values中存在元素类型与数据库的类型匹配就可以了。
pstmt.setObject(i+1,values[i]);
}
}
ResultSet rs = pstmt.executeQuery();//执行SQL语句
while (rs.next()){//取出每一行
T rowData = rowMapper.rowMap(rs);//回调。传入的是rowMapper实现类的对象,就会回调实现的类相应方法
resutlData.add(rowData);
//传入的 sql语句不同,取数据的代码必然不同?如何处理? .多态. 把取数据代表放到某个类的某个方法中,不同查询语句执行代码不一样?
//sql = select * from emp; EmpBean em = new EmpBean() em.setXXX(rs.getXXX)取出emp表的数据放到EmpBean对象中
//sql = select * from Dept; DeptBean d = new DeptBean() d.setXXX(rs.getXXX)取出Dept表的数据放到DeptBean对象中
}
return resutlData;
}finally {
if (connection!=null){
connection.close();//一定要关闭连接
}
}
}
public static ArrayList<Map<String,Object>> queryDataByMap(String sql, Object... values) throws SQLException {
ArrayList<Map<String,Object>> queryResult = new ArrayList<>();//用于存储查询结果
Connection connection = null;
try {
//获得连接
connection = DriverManager.getConnection(url, userName, passWord);
PreparedStatement pstmt = connection.prepareStatement(sql);
//得到可运行SQL的PreparedStatement对象
//根据values的长度(元素个数)循环调用setObject方法
if(values!=null){
for(int i=0;i<values.length;i++){
//之前是用setInt,setString等方法传入与数据库表字段匹配的java类型
//但调用setObject方法时,只要values中存在元素类型与数据库的类型匹配就可以了。
pstmt.setObject(i+1,values[i]);
}
}
ResultSet rs = pstmt.executeQuery();//执行SQL语句
//得到查询结果中的元数据
ResultSetMetaData metaData = rs.getMetaData();
//得到查询结果中的列名
int columnCount = metaData.getColumnCount();
System.out.println("查询结果列数:"+columnCount);
while (rs.next()){//取出每一行
Map<String,Object> rowData = new HashMap<>();
for(int i=1;i<=columnCount;i++){ //取出一行中的每一列
String columnName = metaData.getColumnLabel(i);//列名称()
Object value = rs.getObject(columnName);//根据列名称取得列值
rowData.put(columnName,value);
}
//将rowData (map对象)放到ArrayList中
queryResult.add(rowData);
}
return queryResult;
}finally {
if (connection!=null){
connection.close();//一定要关闭连接
}
}
}
/**
*执行 select 句都可以调用该方法
*
* @param sql 传入insert | update| delete语句
* @param values 第一个参数的SQL语句中存在N个?号,则values传入?号占位符的值
*
*
* @return 返回ResultSet取出的每一行数据,每一行数据放到一个Object[]数组,多行数据放到ArrayList中
*/
@Deprecated
public static ArrayList<Object[]> queryData(String sql,Object... values) throws SQLException {
ArrayList<Object[]> queryResult = new ArrayList<>();//用于存储查询结果
Connection connection = null;
try {
//获得连接
connection = DriverManager.getConnection(url, userName, passWord);
PreparedStatement pstmt = connection.prepareStatement(sql);
//得到可运行SQL的PreparedStatement对象
//根据values的长度(元素个数)循环调用setObject方法
if(values!=null){
for(int i=0;i<values.length;i++){
//之前是用setInt,setString等方法传入与数据库表字段匹配的java类型
//但调用setObject方法时,只要values中存在元素类型与数据库的类型匹配就可以了。
pstmt.setObject(i+1,values[i]);
}
}
ResultSet rs = pstmt.executeQuery();//执行SQL语句
//得到查询结果中的元数据
ResultSetMetaData metaData = rs.getMetaData();
//得到查询结果中的列名
int columnCount = metaData.getColumnCount();
System.out.println("查询结果列数:"+columnCount);
while (rs.next()){//取出每一行
//根据coumnCount取出每一行的值
//创建Object[]数组,长度根据columnCount决定
Object[] rowData = new Object[columnCount];
for(int i=1;i<=columnCount;i++){ //取出一行中的每一列
// System.out.print(rs.getObject(i)+"\t" );
rowData[i-1] = rs.getObject(i);//把列中的数据放到数组中
}
//将rowData放到ArrayList中
queryResult.add(rowData);
}
return queryResult;
}finally {
if (connection!=null){
connection.close();//一定要关闭连接
}
}
}
}