JDBC与JDBC工具类
JDBC与JDBC工具类
小白一枚,正在学习中,做一些笔记防止以后忘记,排版可能也不太好,希望大家见谅
JDBC
JDBC :java 数据库连接,Java语言操作数据库
JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
实现java 与 数据库具体步骤:
- 步骤:
1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
1.复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下
2.右键–>Add As Library
2. 注册/加载驱动
3. 获取数据库连接对象 Connection
4. 定义sql
5. 获取执行sql语句的对象 Statement
6. 执行sql,接受返回结果
7. 处理结果
8. 释放资源
详解:
一、什么是数据库驱动?
数据库驱动是不同数据库开发商(比如oracle mysql等)为了某一种开发语言环境(比如java)能够实现统一的数据库调用而开发的一个程序,他的作用相当于一个翻译人员,将Java语言中对数据库的调用语言通过这个翻译翻译成各个种类的数据库自己的数据库语言,当然这个翻译(数据库驱动)是由各个开发商针对统一的接口自定义开发的
二、我们对JDBC进行编程是为了什么?
JDBC只是提供了一个操作数据库的规则,但具体怎么操作要靠自己编程,我们将要怎么操作的java代码写出来后由数据库驱动去实现这些操作
就好像是一整套规则已经定义在哪,数据库驱动已经将这些规则具体要怎么做已经写了出来,我们要做的是调用这些接口,即我们要选择我们要执行那些规则,我们要做哪些事,我们要做哪些行为,这些就体现在我们编程的代码里,我们调用了哪些接口就是要做哪些事,我们要怎么去做这些事,接口是行为的抽象,我们要进行哪些行为就调用哪些接口,要怎么实现就要看数据库驱动怎么实现它
JDBC只定义接口,具体实现由各个数据库厂商负责。
程序员使用时只需要调用接口,实际调用的是底层数据库厂商的实现部分。
三、注册驱动:
实际上就是将具体的数据库驱动加载进来,我们要操作那个数据库,就要先加载这个数据库的具体实现方法进来,相当于对不同的人有不同的规则操作,要对你进行什么操作首先要确定你是什么人
四、连接数据库:
不同的数据库有不同的连接方式,,要连接数据库,首先要先表明我要连接(jdbc),怎么连接,先看是什么数据库,然后你要做什么操作,这个操作的具体操作怎么做(由数据库驱动搞定),数据库驱动来具体实现这个连接操作
五、执行sql语句的对象
会有一个对象来具体做这些操作,所以我们要先创建出这个对象出来
六、执行sql语句
由执行sql语句的对象执行sql语句,
七、接受结果
执行后,接收结果是什么
使用PreparedStatementt替换Statement*
- 为什么要替换
PreparedStatement能够解决sql语句注入问题
2.什么是sql注入问题
形如 "select * from user where username = ‘lisi’ and password =‘123456’;“这种的sql语句查询数据库是否存在此人时,如果在password中输入a’ or ‘a’ = 'a 那么该sql语句就变成了"select * from user where username = ‘lisi’ and password =‘a’ or ‘a’ = ‘a’;” 该sql语句的语义就发生了变化 就一定能狗登陆成功,如果登陆的是管理员等高权限的用户的话,就会造成数据的不安全,而PreparedStatement使用?占位符解决了该问题,PreparedStatement中该语句为"select * from user where username = ?and password =?;"该sql语句先进行加载,上面的语句就会只是单纯的a’ or ‘a’ = 'a,会在数据库查询该用户的密码是否是这样,不会存在修改sql语句语义的情况,而且提前将sql语句加载进去还可以提高效率
3.如何给?占位符赋值
setXxx(参数1,参数2)
* 参数1:?的位置编号 从1 开始
* 参数2:?的值
抽取JDBC工具类
1.为什么要抽取
java连接数据库要进行加载驱动 获取连接对象 获取执行sql语句 释放资源的对象这一系列动作,但假设我们是对同一数据库的数据进行增删改查,那么每执行一条sql语句我们都要再次加载驱动 获取连接对象,获取执行sql语句的对象,但是这显然是非常麻烦且非常多余的,这些对象及驱动我们只需要执行一次就可以了,因此我们将这些都抽取出来,这样我们执行同一数据库的sql语句时就只用定义sql语句,获取结果就可以,这是很方便的
2.怎么抽取
2.1抽取加载驱动:
2.1.1原本应该如何加载驱动: Class.forName(驱动类的全类名)
2.1.2 现在如何把加载驱动抽取到工具类中
第一步:添加配置文件 配置文件中包含该驱动类的全类名
第二步:读取配置文件,获取配置文件中的驱动类的全类名并用String类型变量接收
第三步:加载驱动 Class.forName(String型变量)
第四步: 读取配置文件以及加载驱动在外部类中都不会在使用,并且只加载一次,所以可以写到静态代码块里面
2.1.3 在外部类里如何使用
获取该类时就自动加载不需要在外部类在写其他代码
2.2抽取获取连接的操作
2.2.1原本应如何获取连接:DriverManager.getConnection(目标数据库,用户名,密码);
2.2.2如何把获取连接对象抽取到jdbc工具类中
第一步:将相应的信息写入到配置文件中 目标数据库 用户名 密码
第二步:读取配置文件,获取配置文件中的相应信息,并将其保存到String类型的url user password中
第三步:获取连接 DriverManager.getConnection(url, user, password);
第四步:获取到的连接对象在其他类中还会再次使用 因此使用静态方法将获取连接对象抽取出来并返回一个Connection型变量 但第一二步与抽取加载驱动的一二步相同,因此这两步就与加载驱动的一二步结合起来使用
2.2.3 在外部类里如何使用
conn = JDBCUtils.getConnection()
2.3抽取关闭资源的操作
2.3.1原本应该如何关闭资源:先判断这些资源是否为null ,在进行关闭资源操作conn.close; state.close; 以及他们的捕获异常操作 ------->如果不先进行判断那么如果在获取的过程中失败了再关闭资源就会出现运行时异常
2.3.2 如何将关闭资源操作抽取
第一步 直接将其操作抽取到一个静态方法里
第二步 将其抽取成重载方法 --------> 参数分别为connection, connection statement, connection statement ResultSet
第三步 仅在参数最多的一个方法里进行判断并关闭资源,在其他的重载方法里调用该方法即可,没有的参数传null即可
2.4 可以在抽取获取连接的时候同时将获取执行sql语句的对象也一起获取。因为获取连接对象仅仅在获取执行sql语句的对象时使用,这样就可以再少写一条代码,具体有没有其他的问题还不明确,但在将statement换成preparedstatement后就不能这样写了,因为preparedstatement需要传入一个sql语句 问过别的大佬说可以这样抽取。
JDBC对数据库数据进行增加操作(抛出异常)
package com.it.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/**
* JDBC:java 数据库连接 ,jdbc就是一个数据库驱动
*
*/
public class ConnectorDemo {
public static void main(String[] args) throws Exception{
//2. 注册驱动
/*
1.Class.forName("驱动类的全路径名称")
2.手动的调用
查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}DriverManager.registerDeiver(new Driver())
3.啥都不用写,自动注册驱动:
mysql驱动jar包5版本之后;
*/
//要使用JDBC接口,需要先将对应数据库的实现部分(驱动)加载进来。
//驱动类加载方式
Class.forName("com.mysql.jdbc.Driver");//这条语句的含义是:装载驱动类,驱动类通过static块实现在DriverManager中的“自动注册”。com.mysql.jdbc.Driver,driver类的全限定修饰符,创建Driver类的对象,静态代码块随着类的加载而加载,就完成了自动注册
//3. 获取数据库连接对象 Connection 具体要连接那个数据库
//Connection接口负责应用程序对数据库的连接,在加载驱动之后,使用url、username、password三个参数,创建到具体数据库的连接。
//当调用方法getConnection , DriverManager将尝试从初始化中加载的驱动程序中找到合适的驱动程序,并使用与当前应用程序相同的类加载器明确加载驱动程序。
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db4","root","root");//DriverManager类实现了连接接口
//4. 定义sql
//你要做什么操作
String s = "INSERT INTO score VALUES(NULL,907, '英语',75);";
//5. 获取执行sql语句的对象 Statement
//Statement接口用来处理发送到数据库的SQL语句对象,通过Connection对象创建。
Statement statement = connection.createStatement();
//6. 执行sql,接受返回结果
// 1. boolean execute(String sql) :可以执行任意的sql 了解
// 2. int executeUpdate(String sql) :执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句
// * 返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。
// 3. ResultSet executeQuery(String sql) :执行DQL(select)语句
int i = statement.executeUpdate(s);
//7. 处理结果,
// 如果是dml操作就返回一个具体数值,代表该操作影响了几行表中数据
//如果是ddl操作就返回一个0,因为ddl是对表进行操作,对表中数据没有任何影响就返回0
//如果是dql操作就返回一个结果集,dql操作结果是一张表,我们用ResultSet来接收这张表
System.out.println(i);
//8. 释放
//调用接口是会占据资源的,我们要释放资源,才能保证内存不会溢出
//该方法显然是不合适的,如果在上面出了错,程序就结束了就不进行到释放资源,资源就一直占着内存
statement.close();
connection.close();
}
}
JDBC对数据库语句进行增加操作
package com.it.jdbc;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class ConnectorAll {
public static void main(String[] args) {
System.out.println(findAll());
}
public static List<ConnectorClass> findAll(){
Connection conn = null;
Statement statement = null;
ResultSet resultSet = null;
ConnectorClass cc;
List<ConnectorClass> connectorClasses = new ArrayList<>();
ArrayList<ConnectorClass> ac = new ArrayList<>();
try {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//创建连接
conn = DriverManager.getConnection("jdbc:mysql:///db4","root","root");
//创建执行对象
statement = conn.createStatement();
//创建sql语句
String s = "SELECT * FROM student;";
//执行sql语句
resultSet = statement.executeQuery(s);
//接收结果,封装对象获得结果集
while (resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String sex = resultSet.getString("sex");
Date birth = resultSet.getDate("birth");
String department = resultSet.getString("department");
String address = resultSet.getString("address");
cc = new ConnectorClass();
cc.setId(id);
cc.setName(name);
cc.setSex(sex);
cc.setBirth(birth);
cc.setDepartment(department);
cc.setAddress(address);
connectorClasses.add(cc);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//关闭资源
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return connectorClasses;
}
}
JDBC工具类
package com.it.jdbc;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtis {
private static String driver;
private static String url;
private static String user;
private static String password;
//创建静态代码块,随着类的加载而加载
static {
try {
//创建properties对象
Properties properties = new Properties();
//加载到内存
ClassLoader classLoader = JDBCUtiss.class.getClassLoader();
//获取配置文件对应的字节流
InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
//读取字节流
properties.load(resourceAsStream);
//获取对应的数据
driver = properties.getProperty("driver");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
//加载驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//连接数据库
public static Connection conn() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
//关闭资源重载
public static void close(Connection conn , PreparedStatement stat){
close(conn,stat,null);
}
public static void close(Connection conn , PreparedStatement stat, ResultSet rs){
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stat != null){
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
工具类的测试类
package com.it.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCShiXian {
public static void main(String[] args) {
//初始化连接对象以及获取sql语句执行的对象
Connection conn = null;
Statement statement = null;
//加载驱动
// 静态代码块自动加载
try {
//获取连接
conn = JDBCUtiss.conn();
//获取执行语句的对象
statement = conn.createStatement();
//sql语句
String s = "INSERT INTO score VALUES(NULL,906, '计算机',90);";
//执行语句
int i = statement.executeUpdate(s);
//获得结果
System.out.println(i);
} catch (SQLException e) {
e.printStackTrace();
} finally {
//关闭资源
JDBCUtils.close(conn,statement);
}
}
}
自己更改后的JDBC工具类(不确定是否有问题)
package com.it.jdbc;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static String driver;
private static String url;
private static String user;
private static String password;
//加载驱动,常与配置文件搭配使用,增强程序的复用性
//仅需加载一次,使用静态代码块的方法加载驱动
static{
try {
//1.加载配置文件
//1.1创建properties对象用于加载配置文件
Properties properties = new Properties();
//1.2获取class目录下的配置文件,使用类加载器将类加载到内存中
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
//1.3获取配置文件资源对应的字节流
InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
//1.4读取字节流
properties.load(resourceAsStream);
//获取配置文件中的数据
driver = properties.getProperty("driver");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
//注册驱动
Class.forName(driver);
//连接数据库 但测试类会使用该连接对象,这样写无法获取到连接对象
//Connection conn = DriverManager.getConnection(url, user, password);
//获取执行sql语句的对象 写到静态代码块里就无法获取到连接对象,因此不能写在里面 获取该对象仅需要一句,因此抽不抽取没有什么意义
//Statement state = conn.createStatement();
} catch (Exception e) {
e.printStackTrace();
}
}
//连接数据库 在获取连接时与此同时也获取了执行sql语句的对象 可以少写一句代码 连接对象仅在获取执行sql语句时使用,因此可以不返回连接对象
/*public static Connection conn() throws SQLException {*/
public static Statement conn() throws SQLException {
Connection conn = DriverManager.getConnection(url, user, password);
return conn.createStatement();
//return DriverManager.getConnection(url,user,password);
}
//关闭资源的重载方法,常在小的重载方法里调用大的重载方法,减少类似的程序
public static void close(Connection conn, Statement statement){
close(conn,statement,null);
}
public static void close(Connection conn, Statement statement, ResultSet resultSet){
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
测试类
package com.it.jdbc;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCText {
public static void main(String[] args) {
//连接数据库判断是否登录成功
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
//1.获取连接
try {
// conn = JDBCUtils.conn();
//2.定义sql
String sql = "SELECT stu_id FROM score;";
//3.获取执行sql的对象
//stmt = conn.createStatement();
stmt = JDBCUtils.conn();
//4.执行查询
rs = stmt.executeQuery(sql);
//5.判断
while (rs.next()){
String stu_id = rs.getString("stu_id");
System.out.println(stu_id);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//JDBCUtils.close(rs,stmt,conn);
}
}
}
下一篇: JS中时间按月份进行有效期判断