Java与数据库连接篇—上

2 篇文章 0 订阅
1 篇文章 0 订阅

Java与数据库连接篇—上

课程内容:

在这里插入图片描述

一、什么是JDBC?(What)

​ JDBC(Java Data Base Connectivity,Java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。

​ Java对外指定一些编程标准,其它数据库服务器厂商按照这个标准,编写对应的实现方案。这样对于Java程序员而言,只需要学习Java的标准即可,不需要了解不同厂商的实现细节。一切操作都是在学习接口开发。按照接口指定的标准完成指定需要完成的业务即可。

二、为什么要使用JDBC?(Why)

  • 为了将数据持久的存储、固化到磁盘上我们需要掌握数据库。
  • 为了通过Java代码完成对于数据的持久存储我们需要学习JDBC。
  • 通过JDBC我们能够以面向接口方式,操作数据库中的数据,更加的方便。
  • 本身Java就是跨平台的,通过Java开发的JDBC应用可以在不同的平台上执行。
  • JDBC为数据库开发提供了标准的API,所以使用JDBC开发的数据库应用也可以跨数据库(要求全部使用标准的SQL)

JDBC和ODBC的区别和联系:

ODBC:

它使用 C 语言接口,是一组对数据库访问的标准API,这些API通过SQL来完成大部分任务,而且它本身也支持SQL语言,支持用户发来的SQL。ODBC定义了访问数据库API的一组规范,这些API独立于形色各异的DBMS和编程语言。

JDBC:

是Java与数据库的接口规范,JDBC定义了一个支持标准SQL功能的通用低层API,它由Java 语言编写的类和接口组成,旨在让各数据库开发商为Java程序员提供标准的数据库API。

常见JDBC驱动:

  • JDBC-ODBC桥(JDBC-ODBC Bridge Driver)
    • 最早实现的JDBC驱动程序,旨在快速推广,将JDBC-API映射为ODBC-API。JDK8中已经移除
  • JDBC API驱动程序(Anative API partly Java technology-enabled Driver)
    • 需要实现本地安装特定的驱动程序,通过转换把Java编写的JDBC-API转换为Native-API,进行数据库操作。
  • 纯Java的数据库中间件驱动程序(Pure Java Driver for Database Middleware)
    • 不需要安装特定的驱动程序,需要在安装数据库管理系统的服务器端安装中间件(Middleware),中间件负责在存取数据时必要的转换操作。就是将JDBC访问转换为数据库无关的http或者是https协议,再有中间件转换为数据库专用的访问指令。
  • 纯Java的JDBC驱动程序(Direct-to-DatabasePureJavaDriver)
    • 目前最流行的JDBC驱动,不需要安装任何附加内容,所有存取数据库的操作都直接由JDBC驱动程序来完成,此类驱动程序能将JDBC调用转换成DBMS专用的网络协议,能够自动识别网络协议下的特殊数据库并能直接创建数据连接。

三、 在那些场景下需要使用JDBC(Where)

Java程序员如果想要和数据库打交道就必须要掌握JDBC。

如果你的业务模型中需要将数据持久化存储就必须掌握JDBC。

更多资料添加QQ:1708434248 v:magejava

四、 如何使用JDBC?(How)

1. JDBC所处的处境?

[外链图片转存失败(img-lDgEyDIq-1562727277939)(img_jdbc\1558841462677.png)]

2.编写第一个JDBC程序

1) 连接步骤
1) 手动导入需要连接数据库的jar包
2) 加载驱动
3) 创建连接对象
4) 声明sql语句
5) 创建处理sql语句对象
6) 发送sql语句,接收返回结果
7) 处理结果
8) 关闭资源连接
2) 导入需要的jar包

连接oracle就导入jdbc的jar包,参照附录到安装对应数据库可以在内部找到jar包;

连接mysql就导入mysql-connector的jar包,到官网下载对应版本jar包,或在maven仓库下载jar包。

3) 编写测试代码
@Test
public void searchOne() {
    //提升作用域 方便后期关闭资源
    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    try {
        //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2:获取连接对象
        conn = DriverManager.getConnection(
            "jdbc:mysql://localhost:3306/note", 
            "root","root");
        //3:声明sql语句
        String sql = "SELECT * FROM TB_USER WHERE ID = 1";
        //4:创建处理对象
        stmt = conn.createStatement();
        //5:发送sql语句获取结果集(如果是查询操作才存在结果集)
        rs = stmt.executeQuery(sql);
        //6. 迭代结果集
        while(rs.next()) {
            //7:分析结果集
            System.out.println(rs.getString("name"));
        }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        //8:关闭资源
        try {
            if(rs!=null) 
                rs.close();
            if(stmt!=null) 
                stmt.close();
            if(conn!=null) 
                conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
4) 分析第一个程序

A. 为什么要加载驱动?

I. 通过Class.forName(“Driver类的路径名”);

II.查看Mysql的Driver类

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
	//在初始化的时候,就将当前数据库对象的驱动加载到sql的注册中心中去
	static {
		try {
			java.sql.DriverManager.registerDriver(new Driver());
		} catch (SQLException E) {
			throw new RuntimeException("Can't register driver!");
		}
	}
}

B.获取连接源码

//获取连接就是会将连接信息包装为Properties
public static Connection getConnection(String url,
                                       String user, String password) throws SQLException {
    java.util.Properties info = new java.util.Properties();

    if (user != null) {
        info.put("user", user);
    }
    if (password != null) {
        info.put("password", password);
    }

    return (getConnection(url, info, Reflection.getCallerClass()));
}

C.常见对象:

对象名称获取方式用途
DriverManager用来管理JDBC驱动的服务类,主要用来获取Connection。
ConnectionDriverManager.getConnection(url,name,pwd);代表一个物理连接会话,如果要操作数据库必须先获取数据库连接对象。
StatementConnection.createStatement();用于执SQL语句的对象。常见的有Statement、PreparedStatement、CallableStatement
ResultSet(针对查询)Statement.executQuery(sql);结果集对象,包含了对于访问查询结果的方法。

3. 修改操作

3.1测试用例编写
@Test
public void updateNameById() {
    //1:声明用户修改的id
    Integer id = 1;
    //2:声明修改后的名称
    String newName= "大锤";
    //3:声明连接对象
    Connection conn = null;
    Statement stmt = null;
    try {
        //4:加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        //5:获取连接对象
        conn = DriverManager.getConnection(
            "jdbc:mysql://localhost:3306/note", 
            "root","root");
        stmt = conn.createStatement();
        //6:声明sql语句
        String sql = "UPDATE TB_USER SET NAME = '"+newName+"'WHERE USERID = "+id;
        //7:发送sql语句 接受返回结果
        int rows = stmt.executeUpdate(sql);
        System.out.println("修改了"+rows+"行记录");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        //8:关闭资源
        try {
            if(stmt!=null) {
                stmt.close();
            }
            if(conn!=null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
3.2 注意事项
1. 修改操作返回的是受影响的行数
2. 加载驱动只需要一次,不需要每次都加载驱动

4. 删除操作

4.1 测试用例编写
public class JDBCTest01 {
	Connection conn = null;
	Statement stmt = null;
	@Before
	public void load() {
		//1:加载驱动
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	@Test
	public void deleteById() {
		try {
			//5:获取连接对象
			conn = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/note", 
					"root","root");
			stmt = conn.createStatement();
			//6:声明sql语句
			String sql =  "DELETE FROM TB_USER WHERE ID = 1";
			//7:发送sql语句 接受返回结果
			int rows = stmt.executeUpdate(sql);
			System.out.println("删除了"+rows+"行记录");
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	
	@After
	public void close() {
		try {
			if(stmt!=null) {
				stmt.close();
			}
			if(conn!=null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}	
4.2 注意事项
* 1:删除操作作为DML语句的一种,返回的也是受影响的行数。

5. 增加操作

5.1 测试用例编写
public class JDBCTest01 {
	Connection conn = null;
	Statement stmt = null;
	@Before
	public void load() {
		//1:加载驱动
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	@Test
	public void insert() {
		try {
			User u = new User("wangdachui", "123456",'王大锤', 18, "男");
			//5:获取连接对象
			conn = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/note", 
					"root","root");
			stmt = conn.createStatement();
			//6:声明sql语句
			String sql =  "INSERT INTO TB_USER (UNAME,UPWD,NAME,AGE,GENDER) VALUES ('"+u.getUname()+"','"+u.getUpwd()+"','"+u.getName()+"','"+u.getAge() + "','" + u.getGender() + "')";
			//7:发送sql语句 接受返回结果
			int rows = stmt.executeUpdate(sql);
			System.out.println("增加了"+rows+"行记录");
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	@After
	public void close() {
		try {
			if(stmt!=null) {
				stmt.close();
			}
			if(conn!=null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

User.java内容如下:

package com.mage.po;
/*
 * javabean规范:
 * 	所有属性私有
 * 所有私有属性提供public的setter、getter方法
 * 提供至少空构造器
 */
public class User {
	private int id;
	private String uname;
	private String upwd;
	private String name;
	private String gender;
	private int age;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getUname() {
		return uname;
	}
	public void setUname(String uname) {
		this.uname = uname;
	}
	public String getUpwd() {
		return upwd;
	}
	public void setUpwd(String upwd) {
		this.upwd = upwd;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public User() {
		super();
		// TODO Auto-generated constructor stub
	}
	public User(int id, String uname, String upwd, String name, String gender, int age) {
		super();
		this.id = id;
		this.uname = uname;
		this.upwd = upwd;
		this.name = name;
		this.gender = gender;
		this.age = age;
	}	
}

更多资料添加QQ:1708434248 v:magejava

5.2 注意事项
删除也是返回受影响的行数

**注意:**对于所有的写操作(增、删、改),其实主体内容都差不多,主要是sql语句不同,某些参数不同,后期是可以考虑封装起来的。

6. 查询操作

6.1 测试用例编写
public class JDBCTest01 {
	Connection conn = null;
	Statement stmt = null;
	ResultSet rs = null;
	@Before
	public void load() {
		//1:加载驱动
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	@Test
	public void insert() {
		LinkedList<User> list = new LinkedList<User>();
		try {
			//5:获取连接对象
			conn = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/note", 
					"root","root");
			stmt = conn.createStatement();
			//6:声明sql语句
			String sql =  "SELECT * FROM TB_USER";
			//7:发送sql语句 接受返回结果
			rs = stmt.executeQuery(sql);
			//8:分析结果集
			while(rs.next()) {
				User u = new User();
				u.setId(rs.getInt("id"));
				u.setUname(rs.getString("uname"));
				u.setUpwd(rs.getString("upwd"));
                u.setName(rs.getString("name"));
				u.setAge(rs.getInt("age"));
				u.setGender(rs.getString("gender"));
				list.add(s);
			}
			
			System.out.println(ls);
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	@After
	public void close() {
		try {
			if(rs!=null) {
				rs.close();
			}
			if(stmt!=null) {
				stmt.close();
			}
			if(conn!=null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
6.2 注意事项
1:对于DQL操作,返回的是结果集ResultSet对象
2:对于ResultSet对象,需要通过.next()方法,查看是否存在其他记录

五、附录

1. Statement对象的问题

1.1 效率问题
  • 正常情况下插入:

问题描述:插入100000条数据,通过Statement插入:root
插入数据:1000,用时:2200

插入数据:1000,用时:2769

插入数据:1000,用时:2943

public class JDBCTest02 {
	Connection conn = null;
	Statement stmt = null;
	ResultSet rs = null;
	
	List<User> data = new LinkedList<>();
	
	@Before
	public void load() {
		try {
			//1:加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			//2:编写测试数据
			for(int i = 1;i<100000;i++) {
				String uname = "zs"+i;
				String upwd = "123";
                String name = "张三"+i;
				int age = (int)(Math.random()*7+18);
				String gender = (int)(Math.random())>0.5?"女":"男";
				User u = new User(uname, upwd,name, age, gender);
				data.add(u);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	@Test
	public void insert() {
		try {
			//5:获取连接对象
			conn = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/note", 
					"root","root");
			stmt = conn.createStatement();
			//记录时间
			long startTime = System.currentTimeMillis();
			int rows = 0;
			for(int i = 1;i<data.size();i++) {
				//6:声明sql语句
				String sql =  "INSERT INTO TB_User (UNAME,UPWD,NAME,AGE,GENDER) VALUES ('"+
						data.get(i).getUname()+"','"+data.get(i).getUpwd()+"','"+							data.get(i).getName()+"','"+ data.get(i).getAge() +"','"+ 							data.get(i).getGender()+"')";
				//7:发送sql语句 接受返回结果
				rows += stmt.executeUpdate(sql);
			}
			//记录时间
			long endTime = System.currentTimeMillis();
			System.out.println(endTime-startTime+"ms,总共受影响的行数是:"+rows);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	@After
	public void close() {
		try {
			if(stmt!=null) {
				stmt.close();
			}
			if(conn!=null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

结论:

399050ms,总共受影响的行数是:100000

  • 通过PreparedStatement插入数据

通过PreparedStatement插入数据

测试用例:

public class JDBCTest03 {
	Connection conn = null;
	PreparedStatement pstmt = null;
	ResultSet rs = null;
	List<User> data = new LinkedList<User>();
	@Before
	public void load() {
		try {
			//1:加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			//2:编写测试数据
			for(int i = 1;i<100000;i++) {
				String uname = "zs"+i;
				String pwd = "123";
                String name = "张三"+i;
				int age = (int)(Math.random()*7+18);
				String gender = (int)(Math.random())==0?"女":"男";
				User u = new User(uname, pwd,name, age, gender);
				data.add(u);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	@Test
	public void insert() {
		int rows = 0;
		try {
			//5:获取连接对象
			conn = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/note", 
					"root","root");
			//6:声明sql语句
			String sql = "INSERT INTO TB_USER(UNAME,UPWD,NAME,AGE,GENDER) VALUES (?,?,?,?,?)";
			//7:获取预处理对象
			pstmt = conn.prepareStatement(sql);
			//记录时间
			long startTime = System.currentTimeMillis();
			//循环获取到每个对象的内容
			for(int i = 0;i<data.size();i++) {
				//8:设置绑定变量
				pstmt.setString(1,data.get(i).getUname());
				pstmt.setString(2,data.get(i).getUpwd());
                pstmt.setString(3,data.get(i).getName());
				pstmt.setInt(4,data.get(i).getAge());
				pstmt.setString(5,data.get(i).getGender());
				//9:发送SQL语句 获取结果
				rows += pstmt.executeUpdate();
			}			
			//记录时间
			long endTime = System.currentTimeMillis();
			
			System.out.println(endTime-startTime+"ms,总共受影响的行数是:"+rows);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	@After
	public void close() {
		try {
			if(pstmt!=null) {
				pstmt.close();
			}
			if(conn!=null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

结论:

677875ms,总共受影响的行数是:100000

  • 通过PreparedStatement批处理以及事务插入数据

通过PreparedStatement批处理插入数据

测试用例:

public class JDBCTest03 {
	Connection conn = null;
	PreparedStatement pstmt = null;
	ResultSet rs = null;
	List<Student> data = new LinkedList<>();
	@Before
	public void load() {
		try {
			//1:加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			//2:编写测试数据
			for(int i = 1;i<100000;i++) {
				String name = "用户"+i;
				String pwd = "123";
				int age = (int)(Math.random()*7+18);
				String gender = (int)(Math.random())>0.5?"女":"男";
				Student stu = new Student(name, pwd, age, gender);
				data.add(stu);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	@Test
	public void insert() {
		int rows = 0;
		try {
			//5:获取连接对象
			conn = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/note?rewriteBatchedStatements=true", 
					"root","root");
			//6:声明sql语句
			String sql = "INSERT INTO TB_USER(UNAME,UPWD,NAMW,AGE,GENDER) VALUES (?,?,?,?,?)";
			//7:获取预处理对象
			pstmt = conn.prepareStatement(sql);
			//记录时间
			long startTime = System.currentTimeMillis();
			//关闭自动提交事务
			conn.setAutoCommit(false);
			//循环获取到每个对象的内容
			for(int i = 0;i<data.size();i++) {
				//8:设置绑定变量
				pstmt.setString(1,data.get(i).getUname());
				pstmt.setString(2,data.get(i).getUpwd());
                pstmt.setString(3,data.get(i).getName());
				pstmt.setInt(4,data.get(i).getAge());
				pstmt.setString(5,data.get(i).getGender());
				//添加到批处理中
				pstmt.addBatch();
			}
			//一起提交到数据库服务器
			rows = pstmt.executeBatch().length;
			//提交事务
			conn.commit();
			//记录时间
			long endTime = System.currentTimeMillis();
			
			System.out.println(endTime-startTime+"ms,总共受影响的行数是:"+rows);
		} catch (SQLException e) {
			try {
				//出现异常则回滚事务
				conn.rollback();;
				e.printStackTrace();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}
	}
	@After
	public void close() {
		try {
			if(pstmt!=null) {
				pstmt.close();
			}
			if(conn!=null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

结论:

188114ms,总共受影响的行数是:100000

  • Tips
    • 使用批处理需要增加rewriteBatchedStatements=true
    • 将所有批量操作添加到一个事务当中,设置自动提交为false;conn.setAutoCommite(false);
    • 如果语句中出现问题,则在异常中对于事务进行回滚。
1.2 SQL注入问题

测试代码:

public class JDBCTest04 {
	Connection conn = null;
	Statement stmt = null;
	ResultSet rs = null;
	public static final String URL = "jdbc:mysql://localhost:3306/note";
	public static final String USER_NAME = "root";
	public static final String USER_PWD = "root";
	//模拟登陆用户
	User user = null;
	
	@Before
	public void load() {
		try {
			//1:加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			//2:模拟用户数据,这里记得在User.java中添加对应构造器
			user = new User("'1","'  or 1=1");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	@Test
	public void queryByUser() {
		int rows = 0;
		try {
			//5:获取连接对象
			conn = DriverManager.getConnection(
					URL, USER_NAME,USER_PWD);
			//6:声明sql语句
			String sql = "SELECT * FROM TB_STUDENT WHERE UNAME = "+loginStu.getUname()
						+" AND PWD = "+loginStu.getUpwd();
			System.out.println(sql);
			//7:获取处理对象
			stmt = conn.createStatement();
			//8:发送sql 获取结果
			rs = stmt.executeQuery(sql);
			//9:分析结果
			while(rs.next()) {
				System.out.println("查询到了结果");
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	@After
	public void close() {
		try {
			if(stmt!=null) {
				stmt.close();
			}
			if(conn!=null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

结论:

  • 通过构建sql语句,导致不同的用户名和密码侵入到系统内部,就是SQL注入攻击。
  • 为了防止出现这个问题,我们通过预处理对象完成,PreparedStatement。

2. 常见方法总结

常见对象对象常见方法作用
ConnectionConnection.createStatement();创建Statement对象
Connection.preparedStatement(sql);创建预处理对象
Connection.prepareCall(sql)创建CallableStatement对象,调用存储过程
Connection.setAutoCommite(true/false)设置事务提交方式,默认情况是自动提交true
Connection.commit();提交事务
Connection.rollback();回滚事务
StatementStatement.executeQuery(sql);针对查询操作,获取结果集对象
Statement.executeUpdate(sql);针对写(增加、删除、修改)操作,获取受影响的行数
PreparedStatementPreparedStatement.executeQuery();针对查询操作,获取结果集对象
PreparedStatement.executeUpdate();针对写(增加、删除、修改)操作,获取受影响的行数
PreparedStatement.addBatch();添加到批处理中
PreparedStatement.executeBatch();执行批处理操作
PreparedStatement.setXXX(index,value);设置绑定变量,给指定的占位符index,指定具体的值value,XXX代表value的数据类型。注意index从1开始
ResultSetResultSet.next();查看读操作返回的结果集中是否还存在数据信息
ResultSet.getXXX(index/columnName);根据字段的顺序或者是字段名称获取结果集中该字段的值,XXX代表返回数据的类型。index获取列是从0开始

3. Statement和PreparedStatement对比

区别点对象具体细节
创建方式StatementConnection.createStatement(); 不需要sql
PreparedStatementConnection.preparedStatement(sql);需要sql
安全Statement不能防止sql注入
SELECT * FROM TB_USER WHERE UNAME = '1 AND PWD = ’ OR 1=1
PreparedStatement可以防止SQL注入
效率Statement不会初始化,没有预处理,每次都是从0开始执行SQ
PreparedStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率
可读性Statement当多次执行参数不同的语句时,需要不断的拼接字符串,使得阅读变得极为耗时以及费力。
PreparedStatement通过SetXXX();这样的方式,提高了阅读性
性能Statement没有预编译的过程,每次都需要在DB中重新编译一下
PreparedStatement语句被db的编译器编译后的执行代码就会被缓存下来, 那么下次调用时只要相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行就可以。 相当于一个函数 , 对于整个db来说,只有预编译的语句和缓存中匹配,那么任何时候,就可以不需要再次编译从而直接执行。并不是所有的预编译语句都会被缓存起来,数据库本身会用一种策略,频繁使用的语句可能被缓存起来,以保存有更多的空间存储新的预编译语句。

3. DBUtiles编写

1) 编写步骤注释
1在src下创建一个.properties文件,编写驱动、链接地址、用户名、密码
2在工具类中通过流的方式读取配置文件信息,获取驱动、链接地址、用户名、密码
3编写获取连接、处理对象的方法
4编写资源连接的方法
2) 具体编码

配置文件DBConfig.properties

database=mysql
#######mysql properties########
mysqlDriver=com.mysql.jdbc.Driver
mysqlUrl=jdbc:mysql://localhost:3306/note
mysqlUsername=root
mysqlPassword=root
#######oracle properties########
oracleDriver=oracle.jdbc.OracleDriver
oracleUrl=jdbc:oracle:thin:@localhost:1521:orcl
oracleUsername=scott
oraclePassword=tiger

编写DBBase接口

public interface DBBase {
	public static final String DATABASE_NAME = "database";
	public static final String DATABASE_DRIVER = "driver";
	public static final String DATABASE_URL = "url";
	public static final String DATABASE_USERNAME = "username";
	public static final String DATABASE_PASSWORD = "password";
}

编写DBUtils工具类

public class DBUtils {
	//声明获取值
	private static String database = "";
	private static String driver = "";
	private static String url = "";
	private static String uname = "";
	private static String pwd = "";
	private static Properties pro = null;
	//通过静态代码块将配置文件信息加载进来
	static {
		try {
			//创建配置对象
			pro = new Properties();
			//获取输入流读取
			InputStream is = Thread.currentThread().getContextClassLoader()
						.getResourceAsStream("DBConfig.properties");
			//读取数据信息
			pro.load(is);
			//通过方法获取配置文件中的数据信息
			database = getValue(DBBase.DATABASE_NAME);
			driver = getValue(database+"-"+DBBase.DATABASE_DRIVER);
			url = getValue(database+"-"+DBBase.DATABASE_URL);
			uname = getValue(database+"-"+DBBase.DATABASE_USERNAME);
			pwd = getValue(database+"-"+DBBase.DATABASE_PASSWORD);
			//加载驱动
			Class.forName(driver);
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			System.out.println("驱动类为【"+driver+"】");
        }
	}
	/**
	 * 获取连接对象
	 * @return
	 */
	public static Connection getConn() {
		Connection conn = null;
		try {
			conn = DriverManager.getConnection(url, uname,pwd);
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println("【"+url+"】【"+uname+"】【"+pwd+"】");
		}
		return conn;
	}
	/**
	 * 创建Statement对象
	 * @param conn
	 * @return
	 */
	public static Statement getState(Connection conn) {
		if(conn==null)
			throw new RuntimeException("连接为空");
		Statement stmt = null;
		try {
			stmt = conn.createStatement();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println("创建Statement对象失败");
		}
		return stmt;
	}
	//关闭连接
	private static void closeConn(Connection conn) {
		if(conn!=null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	//关闭资源
	private static void closeStmt(Statement stmt) {
		if(stmt!=null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
    //关闭资源
	private static void closeRs(ResultSet rs) {
		if(rs!=null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
    //关闭所有资源
	public static void closeAll(Connection conn,Statement stmt,ResultSet rs) {
		closeRs(rs);
		closeStmt(stmt);
		closeConn(conn);
	}
	private static String getValue(String key) {
		if("".equals(key)||key==null)
			throw new NullPointerException("key值有误");
		return pro.getProperty(key);
	}
}

总结

1:通过Properties来加载配置文件信息。
2:通过getContextClassLoader().getResourceAsStream()读取相对于项目根目录下的资源文件。(这里的ClassLoader是一个上下文的加载器)。
3:在获取Properties中的值时,通过异常中断去处理了程序
4:通过静态代码块保证加载驱动只需要执行一次

更多资料添加QQ:1708434248 v:magejava

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值