JavaWeb之 JDBC详解&&JDBC管理事务
JDBC详解&&JDBC管理事务
一、JDBC
1)概念:Java DataBase Connectivity (Java数据库连接),即用Java语言操作数据库
2)JDBC的本质:其实是官方(SUN公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类,即使用的是接口,执行的是实现类
如:
Person接口 Worker类 Person p = new Worker(); p.eat();
二、快速入门
1)步骤:
①导入驱动jar包
②注册驱动
③获取数据库连接对象Connection
④定义sql
⑤获取执行sql语句的对象 Statement
⑥执行sql,接收返回结果
⑦处理结果
⑧释放资源
范例:
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.Statement;
/*
JDBC快速入门
*/
public class JdbcDemo1 {
public static void main(String[] args) throws Exception {
// ①导入驱动jar包,连接什么样的数据库,就导入对应的jar包
// 复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下,Add As Library
// ②注册驱动
Class.forName("com.mysql.jdbc.Driver");
// ③获取数据库连接对象Connection
Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/studytest", "root", "root");
// ④定义sql
String sql = "update account set balance = 1000 where id = 1";
// ⑤获取执行sql语句的对象 Statement
Statement stmt = conn.createStatement();
// ⑥执行sql,接收返回结果
int count = stmt.executeUpdate(sql);
// ⑦处理结果
System.out.println(count);
// ⑧释放资源
stmt.close();
conn.close();
}
}
三、对JDBC中各个接口和类详解
1)DriverManager:驱动管理对象
功能:
①注册驱动:告诉程序该用哪一个数据库驱动jar
static void registerDriver(Driver driver) //注册与给定的驱动程序:DriverManager
代码演示:
Class.forName("com.mysql.jdbc.Driver");
/* com.mysql.jdbc.Driver
类中有一个静态方法可以来注册DriverManager*/
注意:mysql5之后的驱动jar包可以省略注册驱动的步骤
②获取数据库连接
static Connection getConnection(String url,String user,String password)
参数:url:指定的路径、user用户名、password密码
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/studytest", "root", "root");
/*jbdc:mysql://ip地址(域名)//数据库名,
如果连接的是本机mysql服务器,
并且mysql服务默认端口是3306,
则url可简写为:
jdbc:mysql:///数据库名*/
2)Connection:数据库连接对象
功能:
① 获取执行sql对象
Statement createStatement()
PreparedStatement prepareStatement(String sql)
② 管理事务:
开启事务:void setAutoCommit(boolean autoCommit)//调用该方法设置参数为false,即开启事务
提交事务:void commit()
回滚事务:void rollback()
3)Statement:执行sql的对象
boolean execute(String sql)
//可以执行任意的sql
int executeUpdate(String sql)
/*执行DML语句、DDL语句,
返回值是影响的行数,
可以通过影响的行数判断语句是否执行成功,
返回值大于零则成功,反之失败。*/
ResultSet executeQuery(String sql)
//执行DQL(SELECT)语句
4)ResultSet:结果集对象,封装查询结果
next()
:游标向下移动一行
getXxx(参数)
:获取数据,Xxx代表数据类型,如getInt()
参数:
Int代表列的编号,从1开始,如getString(1)
String代表列的名称,如getString(“name”)
范例:
package JdbcDemo;
import java.sql.*;
public class StatementPractice {
public static void main(String[] args) throws Exception {
Statement stmt =null;
Connection conn = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/studytest", "root", "root");
stmt = conn.createStatement();
String sql = "SELECT * FROM account";
rs = stmt.executeQuery(sql);
rs.next(); // 游标向下移动一行
int id = rs.getInt(1);
String name = rs.getString("name");
double balance = rs.getDouble("balance");
System.out.println(id+"---"+name+"---"+balance);
}catch (Exception e){
e.printStackTrace();
}finally {
if (rs!=null)
rs.close();//最后创建最先释放
if (stmt!=null)
stmt.close();//避免空指针异常
if (conn!=null)
conn.close();
}
}
}
遍历结果集:
游标向下移动一行时,先判断是否有数据,再获取数据
next():游标向下移动一行,判断还有没有下一行,如果没有则返回false,如果有则返回true
范例:
while(rs.next()) { // 游标向下移动一行
int id = rs.getInt("id");
String name = rs.getString("name");
double balance = rs.getDouble("balance");
System.out.println(id + "---" + name + "---" + balance);
}
5)PreparedStatement:执行sql的对象,功能更加强大
SQL注入问题:在拼接SQL时,有一些SQL的特殊关键字参与字符串的拼接,会造成安全性问题
解决SQL注入问题:使用PreparedStatement对象来解决,PreparedStatement是一种预编译的SQL,即定义的SQL语句参数使用?作为占位符
方法:Connection. prepareStatement(String sql)
给?赋值:
如:SELECT * FROM emp WHERE id = ? AND name = ?;
方法:setXxx(参数1,参数2); //参数1表示第几个?,参数2表示?代表的值
注意:一般都会使用PreparedStatement来完成增删改查的所有操作,因为其可以防止SQL注入且效率更高
6)Statement练习:
注册驱动Class.forName——创建Connection——创建Statement——写sql——获得结果、处理结果
//account表添加一条记录
package JdbcDemo;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.Statement;
public class StatementPractice {
public static void main(String[] args) throws Exception {
Statement stmt =null;
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/studytest", "root", "root");
stmt = conn.createStatement();
String sql = "INSERT INTO account values(null,'王五',3000)";
int count = stmt.executeUpdate(sql);
System.out.println(count);
}catch (Exception e){
e.printStackTrace();
}finally {
if (stmt!=null)
stmt.close();//避免空指针异常
if (conn!=null)
conn.close();
}
}
}
7)SELECT练习:定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回
范例:
package JdbcDemo;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class empPractice {
public static void main(String[] args) throws SQLException {
List<Emp> list = new empPractice().findAll();
System.out.println(list);//打印的时emp的重写的toString方法
}
public List<Emp> findAll() throws SQLException {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
List<Emp> list = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql:///studytest","root","root");
stmt = conn.createStatement();
String sql = "SELECT * FROM emp";
rs = stmt.executeQuery(sql);
Emp emp = null;
list = new ArrayList<Emp>();
while (rs.next()) {
int id = rs.getInt("id");
String ename = rs.getString("ename");
int job_id = rs.getInt("job_id");
int mgr = rs.getInt("mgr");
Date joindate = rs.getDate("joindate");
double salary = rs.getDouble("salary");
double bonus = rs.getDouble("bonus");
int dept_id = rs.getInt("dept_id");
emp = new Emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id);
list.add(emp);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if (rs != null)
rs.close();
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
}
return list;
}
}
8)抽取JDBC工具类:JDBCUtils
范例:
package Util;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
/*
* 文件的读取,只需读取一次即可拿到这些值。使用静态代码块
* */
static {
//读取资源文件,获取值
Properties pro = new Properties();
//获取src路径下的文件的方式-->ClassLoader 类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
try {
pro.load(new FileReader(path));
} catch (IOException e) {
e.printStackTrace();
}
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/*
* 获取连接
* @return 连接对象
* */
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
public static void close(Statement stmt,Connection conn){
if (stmt!=null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void close(Statement stmt, Connection conn, ResultSet rs){
if (stmt!=null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (rs!=null) {
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
目的:简化书写,不用为了简单的查询目标而书写过多重复的创建对象语句
1.抽取注册驱动
2.抽取一个方法获取连接对象:需求:不想传递参数,还得保证工具类的通用性——解决方案:配置文件
范例:
url=jdbc:mysql:///studytest
user=root
password=root
driver=com.mysql.jdbc.Driver
3.抽取一个方法释放资源:方法重载
9)JDBC控制事务:
事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败
使用Connection对象来管理事务:
开启事务:setAutoCommit(boolean autoCommit):
调用该方法设置参数为false,即开启事务
提交事务:commmit()
回滚事务:rollback()
案例:事务实现转账问题,account表中有张三李四分别拥有1000元,实现张三转给李四500元
范例:
package JdbcDemo;
import Util.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
/*
* 事务操作
* */
public class AccountCommitDemo {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;
try {
//获取连接
conn = JDBCUtils.getConnection();
//开启事务
conn.setAutoCommit(false);
//定义SQL
String sql1 = "Update account set balance = balance - ? where id = ?";
String sql2 = "Update account set balance = balance + ? where id = ?";
//获取sql对象
pstmt1 = conn.prepareStatement(sql1);
pstmt2 = conn.prepareStatement(sql2);
//设置参数
pstmt1.setDouble(1,500);
pstmt1.setInt(2,1);
pstmt2.setDouble(1,500);
pstmt2.setInt(2,2);
pstmt1.executeUpdate();
pstmt2.executeUpdate();
//没有问题则提交事务
conn.commit();
} catch (SQLException throwables) {
throwables.printStackTrace();
//出现异常时回滚事务
if (conn!=null){
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
finally {
JDBCUtils.close(pstmt1,conn);
JDBCUtils.close(pstmt2,null);
}
}
}