目录
(一)为什么要使用JdbcUtil工具类
问题:
- 在编写jdbc的时候,在每一句sql语句以及功能的实现时,有大量重复的代码,如获取Connection,关闭资源...
- 数据库四大参数,写在代码中,硬编码(后期需要连接其他的数据库时,可能需要把代码改掉,换个环境就要改代码,修改配置参数,就要就该代码,造成不便)
解决方案:
- 封装思维 ,解决大量代码重复问题,将一样的代码取出来,加载驱动类只需要一次就行了
- 配置文件:properties文件
(二)创建一个prorperties文件
1.在文件目录或src目录下,选择新建FIle
2.创建properties文件
3.编写配置文件
把配置参数引入到properties文件里面
使用Properties格式配置文件
#注释 key=value
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/esa?useUnicode=true&characterEncoding=utf8
username=root
password=123456
为什么要使用Properties?
- Properties文件不需要像xml一样去手动解析, jdk有一个对应类:java.util.Properties,是Map接口实现类,但是key,value都是String类型
- Properties可以通过load方法,读取Properties文件,解析数据,变成key/value结构,存储到Properties对象
Java基础:反射
反射(
Reflection
),Java 中的反射机制是指,Java 程序在运行期间可以获取到一个对象的全部信息。反射机制一般用来解决Java 程序运行期间,对某个实例对象一无所知的情况下,如何调用该对象内部的方法问题。
4.获取资源的方式
不同的方式对存放文件的目录有要求
第一种
放在项目下面
Properties prop=new Properties();
//读取db.properties文件
//FileInputStream("文件名"); 相对路径:相对于user.dir
//user.dir 系统参数 当前项目路径
//D:\作业\jdbc-demo1
System.out.println(System.getProperty("user.dir"));
//FileInputStream("文件名"); 相对路径:相对于user.dir
prop.load(new FileInputStream("db.properties"));
//TestProperties.class.getResourceAsStream("db.properties");System.out.println(prop.getProperty("driverClass"));
第二种
放在同一个包下面
Properties prop=new Properties();
//读取db.properties文件
//FileInputStream("文件名"); 相对路径:相对于user.dir
//user.dir 系统参数 当前项目路径
//D:\作业\jdbc-demo1
//System.out.println(System.getProperty("user.dir"));
//FileInputStream("文件名"); 相对路径:相对于user.dir
//prop.load(new FileInputStream("db.properties"));
//TestProperties.class.getResourceAsStream("db.properties"); 要求:文件与这个类在同一个目录下
InputStream in=TestProperties.class.getResourceAsStream("db.properties");
System.out.println(in);
prop.load(in);
//获取数据
System.out.println(prop.getProperty("driverClass"));
报错:
原因:
TestProperties.class.getClassLoader().getResourceAsStream("db.properties");
要求:文件与这个类在同一个目录下
将这个包移动到与类同目录即可
解决成功:
第三种
获取类加载器,放在src下面
Properties prop=new Properties();
//读取db.properties文件
//FileInputStream("文件名"); 相对路径:相对于user.dir
//user.dir 系统参数 当前项目路径
//D:\作业\jdbc-demo1
//System.out.println(System.getProperty("user.dir"));
//FileInputStream("文件名"); 相对路径:相对于user.dir
//prop.load(new FileInputStream("db.properties"));
//TestProperties.class.getResourceAsStream("db.properties"); 要求:文件与这个类在同一个目录下
// InputStream in=TestProperties.class.getResourceAsStream("db.properties");
// System.out.println(in);
// prop.load(in);
//getClassLoader() 获取类加载器
InputStream in=TestProperties.class.getClassLoader().getResourceAsStream("db.properties");
System.out.println(in);
prop.load(in);
//获取数据
System.out.println(prop.getProperty("driverClass"));
(三)编写JdbcUtil工具类
1.可变参数
定义一个方法,对数组元素进行相加的方法
方法一:
通常我们会使用for循环来进行相加,但是在main方法里,需要定义一个长度不可变,数组里面的数据也定义好了的数组。
代码实现:
public static int sum(int[] nums){
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
return sum;
}public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
int sum = sum(arr);
System.out.println(sum);
}控制台输出:
输出是没有问题的,但是定义一个数组,需要多几行代码,如果我们需要使用
System.out.println(sum(arr,1,2,3,4,5,6,7,8,9,10));这个语句来进行计算,是会报错的,因为在现在这个方法里面,参数是固定的,那么就要使用可变数组了。
方法二(可变参数):
java中有一个语法:
可变参数: 数据类型... 参数名 本质数组
限制:
- 可变参数只能是最后一个参数
一个方法只能有一个可变参数,不能有多个,如果是数组,一个方法可以有多个数组参数
代码实现:
/**
* 可变参数
*/
public class Test {
//定义一个方法,对数组元素进行相加的方法
//java中有一个语法: 可变参数: 数据类型... 参数名 本质数组
//限制: 可变参数只能是最后一个参数
// 一个方法只能有一个可变参数,不能有多个,如果是数组,一个方法可以有多个数组参数
public static int sum(int... nums){
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
return sum;
}public static void main(String[] args) {
// int[] arr = {1,2,3,4,5};
// int sum = sum(arr);
System.out.println(sum(4,9,10,22,11,34));
}
}控制台输出:
结果正确!!!
2.执行增删改sql语句
编写JdbcUtil工具类,封装代码,减少重复代码
将获取连接以及加载数据参数的代码封装起来,执行sql语句的方法,在测试类中只需要写sql语句就行了,大大减少了重复代码
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class JdbcUtils {
static Properties prop=new Properties();
//使用静态代码块 加载数据库四大参数
static {
InputStream in=JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
try {
prop.load(in);
Class.forName(prop.getProperty("driverClass"));
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}/**
* 获取连接对象
* @return Connection对象
*/
public static Connection getConnection() throws SQLException {
String jdbcUrl=prop.getProperty("jdbcUrl");
String username=prop.getProperty("username");
String password=prop.getProperty("password");
return DriverManager.getConnection(jdbcUrl,username,password);
}/**
* 关闭连接对象
*/
public static void close(Connection conn, PreparedStatement stmt, ResultSet rs){
try{
if (rs!=null) rs.close();
if (stmt!=null) stmt.close();
if (conn!=null) conn.close();
}catch (SQLException e){
throw new RuntimeException(e);
}
}/**
* 执行增删改的sql的方法
*/
public static int executeUpdate(String sql,Object... params){
//ctrl + alt + t 把代码使用指定的方法包裹起来
Connection conn=null;
PreparedStatement pstmt=null;
try {
conn=getConnection();
pstmt= conn.prepareStatement(sql);
for (int i=0;i<params.length;i++){
pstmt.setObject(i+1,params[i]);
}
return pstmt.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
close(conn,pstmt,null);
}}
}
使用测试类,检测代码能否运行成功
增删改调用executeUpdate方法
public class TestJdbcUtil {
public static void main(String[] args) {
//执行增删改sql
String sql="delete from tb_user where username = ? and password = ?";
int count=JdbcUtils.executeUpdate(sql,"zhangsan","123");
if(count>0){
System.out.println("删除成功");
}else{
System.out.println("删除失败");
}
}
}运行结果:
删除成功,表中已没有zhangsan这条数据
3.执行查询语句
标签:JDBC,java,--,System,prop,int,Properties,sql,properties From: https://blog.csdn.net/2301_76890677/article/details/143626430查询相较于增删改复杂一些,就比如在关闭资源这一块
执行代码:
public class TestJdbcUtil {
public static void main(String[] args) {//执行查询sql
String sql="select * from tb_user where username = ? and password = ?";
ResultSet rs=null;
try {
rs=JdbcUtils.executeQuery(sql,"lisi","456");
while (rs.next()){
String username=rs.getString("username");
String password=rs.getString("password");
System.out.println(username+"--"+password);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.close(null,null,rs);
}
}
}工具类的实现:
public static ResultSet executeQuery(String sql,Object... params) throws SQLException{
Connection conn=null;
PreparedStatement pstmt=null;
conn=getConnection();
pstmt= conn.prepareStatement(sql);
for (int i=0;i<params.length;i++){
pstmt.setObject(i+1,params[i]);
}
ResultSet rs=pstmt.executeQuery();
close(conn,pstmt,null);
return rs;
}运行结果:
报错: java.sql.SQLException: Operation not allowed after ResultSet closed
因为先把conn和pstmt关闭,那么ResultSet也就没意义了,这也是为什么要倒序关闭的原因,数据会无法传过来
解决方法:
1.在JdbcUtil工具类中修改close()方法,把Connection和PreparedStatement两个属性提取出来,变成静态属性
2.将close()需要传入的参数变成只有ResultSet一个,但是方法中仍然需要关闭Connection和PreparedStatement资源
3.修改其他方法中用到的close()方法
运行:
成功!!
但是这样写只能在单线程中没有问题,在多线程中有问题,多线程在于数据共享,当线程a执行完了,把资源关闭后,那么线程b就无法使用这个资源,所以代码还需要改进