JDBC规范是13种JAVAEE规范中的一种。其制定了Java与所有的【关系型数据库服务器(Oracle,sqlServer,mySql)】在进行联合开发时遵守规则,包括开发步骤以及涉及的接口,相关接口来自JDK中java.sql
包。
JDBC规范中,只提供了开发时需要的接口并没有提供具体实现类,具体实现类由数据库服务器厂商提供,通过jar包形式提供
Driver
)。来了解本次进行交流的数据库服务器类型,便于JVM对推送的SQL命令编译Connection
)PreparedStatement
)ResultSet
)交给交通工具,返回给当前Java类com.mysql.jdbc.Driver
MySql
提供jar
包,用于通知JVM
本次访问的数据库服务器类型。此时JVM
根据信息,将推送的SQL
命令进行对应的编译java.sql.Connection
接口Connection
接口修饰的对象,用于管理Java类与数据库服务器之间链接通道,开发人员习惯于将Connection
接口修饰的对象称为【连接对象】java.sql.Statement
接口(淘汰)Statement
接口修饰的对象,用于管理链接通道上的【交通工具】开发人员习惯于将Statement
接口修饰的对象称为【数据库操作对象】java.sql. PreparedStatement
接口Statement
接口的升级版,可以防止SQL
注入,比Statement
接口(编译n次,执行n次)执行速度快(编译一次,执行n次)
PreparedStatement
是如何防止SQL注入?使用 Statement 往sql语句中传递参数时,只是简单的字符串拼接,有SQL注入的风险:
SELECT COUNT(*) FROM EMP WHERE ENAME=yang or 1=1 AND PASSWORD=123
而使用
PreparedStatement
时,PreparedStatement
要求将SQL命令需要使用参数地方用"?
"替换String sql ="select count(*) from emp where ename = ? and password = ?"
在执行时由
PreparedStatement
负责将外部的参数添加到占位符上,PreparedStatement
将所有参数都作为字符串类型赋值,此时的sql就会变成如下的格式,可见,有效的防止的SQL注入:SELECT COUNT(*) FROM EMP WHERE ENAME='yang or 1=1' AND PASSWORD='123'
java.sql.ResultSet
接口MySql
接收到查询命令时,将查询得到临时表作为货物返回给Java类,在Java类使用ResutlSet
接口来管理接收到临时表。通常将ResultSet
接口修饰的对象称为【结果集】public class Test1 {
public static void main(String[] args) throws Exception {
//货物
String sql = "INSERT INTO DEPT VALUE(901,'小额贷款部门2','福建')";
//1.通知JVM加载Driver类,让JVM了解本次进行交流的数据库服务器类型,便于进行对应编译
Class.forName("com.mysql.jdbc.Driver");
//2.在当前类文件与MySQL服务器之间建立一个链接通道
/*
* 第一个参数:访问的数据库地址
* jdbc:mysql://mysql服务器IP地址:服务器端口号/访问数据库名称
* 例子:
* "jdbc:mysql://localhost:3306/bjpowernode"
*
* 第二个参数: 登录名 "root"
*
* 第三个参数: 登录密码 "123"
*/
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123");
//2.在链接通道上创建一个交通工具 【数据库操作对象】
Statement st = con.createStatement();
//3.将SQL命令作为货物装上交通工具,由交通工具负责将SQL命令推送给MySql服务器来执行,并带回执行结果
//executeUpdate只能推送用于修改数据行命令,比如 INSERT ,DELETE ,UPDATE,但是不能推送SELECT
int result = st.executeUpdate(sql);
if (result > 0) {
System.out.println("插入成功");
} else {
System.out.println("插入失败");
}
//4.将交通工具和链接通道依次销毁
if (st != null) {
st.close();
}
if (con != null) {
con.close();
}
}
}
public class Test1 {
public static void main(String[] args) throws Exception {
//货物
String sql = "select * from t where id=1";
//1.通知JVM加载Driver类,让JVM了解本次进行交流的数据库服务器类型,便于进行对应编译
Class.forName("com.mysql.jdbc.Driver");
//2.在当前类文件与MySQL服务器之间建立一个链接通道
/*
* 第一个参数:访问的数据库地址
* jdbc:mysql://mysql服务器IP地址:服务器端口号/访问数据库名称
* 例子:
* "jdbc:mysql://localhost:3306/bjpowernode"
*
* 第二个参数: 登录名 "root"
*
* 第三个参数: 登录密码 "123"
*/
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123");
//2.在链接通道上创建一个交通工具 【数据库操作对象】
Statement st = con.createStatement();
//3.将SQL命令作为货物装上交通工具,由交通工具负责将SQL命令推送给MySql服务器来执行,并带回执行结果
//执行sql的查询语句,查询结果封装在resultSet中。
ResultSet rs = st.executeQuery(sql);
while (rs.next()) {
//通过resultSet.getXXX()来获取查询出的结果。
//其中XXX表示数据的类型,可以通过形参来指定数据的列
}
//4.将交通工具和链接通道依次销毁
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (con != null) {
con.close();
}
}
}
关键:要取消 Connection
的自动提交:con.setAutoConnmit(flase);
public class Main {
public static void main(String[] args) throws Exception {
String sql_1 = "insert into emp (empno,ename,deptno) value(555,'小崔',200)";
String sql_2 = "insert into dept(deptno,dname,loc) value(200,'dept_200','bj')";
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123");
//通知MySQL服务器,要求获得一个事务对象管理权
con.setAutoCommit(false);// 通知MySql,由当前通道推送过来的所有SQL命令都要交给同一个事务对象管理,这个事务对象管理权由当前的通道Connection对象负责
PreparedStatement ps = con.prepareStatement("");//空车
try {
ps.executeUpdate(sql_1);// sql_1------>transaction——1对象
ps.executeUpdate(sql_2);// sql_2------>transaction——1对象
//此时通知事务对象,将本次备份的信息全部删除
con.commit(); // commit;
} catch (SQLException ex) {
//推送的SQL命令中至少有一条不能正常执行的,此时通知事务对象将事务中所有的SQL命令都设置为无效
con.rollback(); // rollback
ex.printStackTrace();
}
if (ps != null) {
ps.close();
}
if (con != null) {
con.close();
}
}
}
JDBC开发步骤:
抽取出内容相对固定操作步骤封装成工具类
public class DBUtil {
private static final String url = "jdbc:mysql://localhost:3306/bjpowernode";
private static final String root = "root";
private static final String password = "123";
private static Connection con = null;
private static PreparedStatement ps = null;
//1.加载Driver类
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//2.创建连接通道
public static Connection getConnection() throws Exception {
con = DriverManager.getConnection(url, root, password);
return con;
}
//3.创建交通工具
public static PreparedStatement createStatement(String sql) {
try {
getConnection();
ps = con.prepareStatement(sql);
} catch (Exception e) {
e.printStackTrace();
}
return ps;
}
//4.销毁相关资源(ps,con)
public static void close(ResultSet rs) {
try {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
if (con != null) {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
在JDBC的操作中,主要是Connection
连接对象的创建和销毁比较耗时间,可以通过监听器对象在项目启动阶段创建Connection
,并保存到全局作用域对象中作为共享数据,在网站关闭时对Connection
对象进行销毁。
public class OneListener implements ServletContextListener {
//在项目【启动阶段】创建20个Connection,存入到全局作用域对象
@Override
public void contextInitialized(ServletContextEvent event) {
Map map = new HashMap();
//1.创建20个Connection
for (int i = 1; i <= 20; i++) {
try {
Connection con = DBUtil.getConnection();
map.put(con, true);//true 空闲 false被占用
System.out.println("在项目启动时,创建Connection " + con);
} catch (Exception e) {
e.printStackTrace();
}
}
//2.将map管理的20个Connection保存到全局作用域对象,作为共享数据
ServletContext application = event.getServletContext();
application.setAttribute("数据库连接池", map);
}//map
//在网站关闭时,将网站用过的20个Connection进行销毁
@Override
public void contextDestroyed(ServletContextEvent event) {
//1.得到即将被销毁的Connection
ServletContext application = event.getServletContext();
//2.从application得到20个Connection,依次销毁
Map map = (Map) application.getAttribute("数据库连接池");
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
Connection con = (Connection) it.next();
System.out.println("在项目关闭期间,销毁Conection " + con);
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}