JDBC
JDBC的入门
JDBC API 允许用户访问任何形式的表格数据,尤其是存储在关系数据库中的数据。
执行流程:
连接数据源,如:数据库。
为数据库传递查询和更新指令。
处理数据库响应并返回的结果。
什么是JDBC
JDBC 规范定义接⼝,具体的实现由各⼤数据库⼚商来实现。
JDBC 是 Java 访问数据库的标准规范,真正怎么操作数据库还需要具体的实现类,也就是数
据库驱动。每个数据库⼚商根据⾃家数据库的通信格式编写好⾃⼰数据库的驱动。所以我们只需
要会调⽤ JDBC 接⼝中的⽅法即可,数据库驱动由数据库⼚商提供。
使⽤JDBC的好处:
- 程序员如果要开发访问数据库的程序,只需要会调⽤ JDBC 接⼝中的⽅法即可,不⽤关
注类是如何实现的。 - 使⽤同⼀套 Java 代码,进⾏少量的修改就可以访问其他 JDBC ⽀持的数据库。
JDBC的架构
分为双层架构和三层架构。
双层
作用:此架构中,Java Applet 或应用直接访问数据源。
条件:要求 Driver 能与访问的数据库交互。
机制:用户命令传给数据库或其他数据源,随之结果被返回。
部署:数据源可以在另一台机器上,用户通过网络连接,称为 C/S配置(可以是内联网或互联网)。
三层
侧架构特殊之处在于,引入中间层服务。
流程:命令和结构都会经过该层。
吸引:可以增加企业数据的访问控制,以及多种类型的更新;另外,也可简化应用的部署,并在多数情况下有性能优势。
历史趋势: 以往,因性能问题,中间层都用 C 或 C++ 编写,随着优化编译器(将 Java 字节码 转为 高效的 特定机器码)和技术的发展,如EJB,Java 开始用于中间层的开发这也让 Java 的优势突显出现出来,使用 Java 作为服务器代码语言,JDBC随之被重视。
使⽤JDBC开发使⽤到的包
会使⽤到的包 | 说明 |
---|---|
java.sql | 所有与 JDBC 访问数据库相关的接⼝和类 |
javax.sql | 数据库扩展包,提供数据库额外的功能。如:连接池 |
数据库的驱动 | 由各⼤数据库⼚商提供,需要额外去下载,是对 JDBC 接⼝实现的类 |
JDBC的核⼼API
接⼝或类 | 作⽤ |
---|---|
DriverManager 类 | 1. 管理和注册数据库驱动2. 得到数据库连接对象 |
Connection 接⼝ | ⼀个连接对象,可⽤于创建 Statement 和 PreparedStatement对象 |
Statement 接⼝ | ⼀个 SQL 语句对象,⽤于将 SQL 语句发送给数据库服务器。 |
PreparedStatement 接⼝ | ⼀个 SQL 语句对象,是 Statement 的⼦接⼝ |
ResultSet 接⼝ | ⽤于封装数据库查询的结果集,返回给客户端 Java 程序 |
加载和注册驱动
加载和注册驱动的⽅法 | 描述 |
---|---|
Class.forName(数据驱动实现类) | 加载和注册数据库驱动,数据库驱动由 MySQL ⼚商"com.mysql.jdbc.Driver" |
DriverManager类
DriverManager 作⽤
- 管理和注册驱动
- 创建数据库的连接
类中的⽅法
DriverManager 类中的静态⽅法 | 描述 |
---|---|
Connection getConnection (String url, String user,String password) | 通过连接字符串,⽤户名,密码来得到数据库的连接对象 |
Connection getConnection (String url, Propertiesinfo) | 通过连接字符串,属性对象来得到连接对象 |
使⽤JDBC连接数据库的四个参数
JDBC连接数据库的四个参数 | 说明 |
---|---|
⽤户名 | 登录的⽤户名 |
密码 | 登录的密码 |
连接字符串 URL | 不同的数据库 URL 是不同的,mysql 的写法jdbc:mysql://localhost:3306/数据库[?参数名=参数值] |
驱动类的字符串名 | com.mysql.jdbc.Driver |
连接数据库
- 使用用户名、密码、URL得到连接对象
public class Demo2 {
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost:3306/java2106";
Connection connection = DriverManager.getConnection(url, "root","123wang456");
System.out.println(connection);
}
}
- 使用属性文件和URL得到连接对象
public class Demo3 {
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost:3306/java2106";
Properties prop = new Properties();
prop.setProperty("user", "root");
prop.setProperty("password", "123wang456");
Connection connection = DriverManager.getConnection(url, prop);
System.out.println(connection);
}
}
数据库工具类JDBCUtils
public class JDBCUtils {
private static String url;
private static String driver;
private static String username;
private static String password;
static {
Properties pro = new Properties();
try {
pro.load(JDBCUtils.class.getResourceAsStream("JDBCmsg.properties"));
driver = pro.getProperty("jdbc.driver");
url = pro.getProperty("jdbc.url");
username = pro.getProperty("jdbc.userName");
password = pro.getProperty("jdbc.password");
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
try {
return DriverManager.getConnection(url,username,password);
} catch (SQLException throwables) {
throwables.printStackTrace();
return null;
}
}
}
PreparedStatement接口
Connection 创建 PreparedStatement对象
Connection 接⼝中的⽅法 | 描述 |
---|---|
PreparedStatementprepareStatement(String sql) | 指定预编译的 SQL 语句,SQL 语句中使⽤占位符? 创建⼀个语句对象 |
PreparedStatement接口中的对象
PreparedStatement 接⼝中的⽅法 | 描述 |
---|---|
int executeUpdate() | 执⾏ DML,增删改的操作,返回影响的⾏数。 |
ResultSet executeQuery() | 执⾏ DQL,查询的操作,返回结果集 |
PreparedSatement 的好处
- prepareStatement()会先将 SQL 语句发送给数据库预编译。PreparedStatement 会引⽤着
预编译后的结果。可以多次传⼊不同的参数给 PreparedStatement 对象并执⾏。减少 SQL
编译次数,提⾼效率。 - 安全性更⾼,没有 SQL 注⼊的隐患。
- 提⾼了程序的可读性。
PreparedSatement的使用
public class Demo03 {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
String username = sc.nextLine();
String password = sc.nextLine();
Connection conn = JDBCUtils.getConnection();
String sql = "select * from user2 where username = ? and password = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1,username);
stmt.setString(2,password);
ResultSet rs = stmt.executeQuery();
if(rs.next()){
System.out.println("登陆成功");
}else {
System.out.println("登录失败");
}
rs.close();
stmt.close();
conn.close();
}
}
案例
使⽤ PreparedStatement 查询⼀条数据,封装成⼀个Emp 对象
public class Demo04Emp {
// 新增
public void addEmp(Emp emp) {
Connection conn = JDBCUtils.getConnection();
String sql = "insert into emp values (?,?,?,?,?,?,?,?)";
PreparedStatement stmt = null;
try {
stmt = conn.prepareStatement(sql);
stmt.setInt(1,emp.getEmpno());
stmt.setString(2,emp.getEname());
stmt.setString(3,emp.getJob());
stmt.setInt(4,emp.getMgr());
stmt.setDate(5, (Date) emp.getHiredate());
stmt.setDouble(6,emp.getSal());
stmt.setDouble(7,emp.getComm());
stmt.setInt(8,emp.getDeptno());
stmt.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if(stmt != null){
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
// 根据id删除
public void deleteById(int empno) {
Connection conn = JDBCUtils.getConnection();
String sql = "delete from emp where empno = ?";
PreparedStatement stmt = null;
try {
stmt = conn.prepareStatement(sql);
stmt.setInt(1,empno);
stmt.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if(stmt != null){
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
// 根据id查询
public Emp findById(int empno) {
Connection conn = JDBCUtils.getConnection();
String sql = "select * from emp where empno = ?";
PreparedStatement stmt = null;
ResultSet rs = null;
Emp emp = new Emp();
try {
stmt = conn.prepareStatement(sql);
stmt.setInt(1,empno);
rs = stmt.executeQuery();
while (rs.next()){
emp.setEmpno(rs.getInt(1));
emp.setEname(rs.getString(2));
emp.setJob(rs.getString(3));
emp.setMgr(rs.getInt(4));
emp.setHiredate(rs.getDate(5));
emp.setSal(rs.getDouble(6));
emp.setComm(rs.getDouble(7));
emp.setDeptno(rs.getInt(8));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if(rs != null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(stmt != null){
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return emp;
}
// 查询全部(分页)
public List<Emp> findList(int page, int pageSize){
Connection conn = JDBCUtils.getConnection();
String sql = "select * from emp limit ?,?";
PreparedStatement stmt = null;
ResultSet rs = null;
List<Emp> list = new ArrayList<>();
try {
stmt = conn.prepareStatement(sql);
stmt.setInt(1,(page-1)*pageSize);
stmt.setInt(2,pageSize);
rs = stmt.executeQuery();
while (rs.next()){
Emp emp = new Emp();
emp.setEmpno(rs.getInt(1));
emp.setEname(rs.getString(2));
emp.setJob(rs.getString(3));
emp.setMgr(rs.getInt(4));
emp.setHiredate(rs.getDate(5));
emp.setSal(rs.getDouble(6));
emp.setComm(rs.getDouble(7));
emp.setDeptno(rs.getInt(8));
list.add(emp);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return list;
}
// 修改
public void update(Emp emp) {
Connection conn = JDBCUtils.getConnection();
PreparedStatement stmt = null;
String sql = "update emp set empno = ?,ename = ?,job = ?," +
"mgr = ?,hiredate = ?,sal = ?,comm = ?,deptno = ? where empno = ?";
try {
stmt = conn.prepareStatement(sql);
stmt.setInt(1,emp.getEmpno());
stmt.setString(2,emp.getEname());
stmt.setString(3,emp.getJob());
stmt.setInt(4,emp.getMgr());
stmt.setDate(5,(Date)emp.getHiredate());
stmt.setDouble(6,emp.getSal());
stmt.setDouble(7,emp.getComm());
stmt.setInt(8,emp.getDeptno());
stmt.setInt(9,emp.getEmpno());
stmt.executeUpdate();
stmt.close();
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
//查询总记录条数
public int getCount(){
Connection conn = JDBCUtils.getConnection();
PreparedStatement stmt = null;
ResultSet rs = null;
String sql = "select count(*) from emp";
int count = 0;
try {
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
if(rs.next()){
count = rs.getInt(1);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return count;
}
}
public class Demo06Main {
Demo04Emp demo04Emp;
@Before
public void testBefore(){
demo04Emp = new Demo04Emp();
}
@Test
public void testAdd(){
Emp emp = new Emp(7451,"MIKE","SALESMAN",
7698,null,1600,200,20);
demo04Emp.addEmp(emp);
}
@Test
public void testDeleteById(){
demo04Emp.deleteById(7451);
}
@Test
public void testFindById(){
demo04Emp.findById(7369);
}
@Test
public void testFindList(){
demo04Emp.findList(1,1);
}
@Test
public void testUpdate(){
// demo04Emp.update();
}
@Test
public void testGetCount(){
demo04Emp.getCount();
}
}
public class Emp {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;
public Emp() {
}
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Integer getMgr() {
return mgr;
}
public void setMgr(Integer mgr) {
this.mgr = mgr;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
public Double getComm() {
return comm;
}
public void setComm(Double comm) {
this.comm = comm;
}
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", mgr=" + mgr +
", hiredate=" + hiredate +
", sal=" + sal +
", comm=" + comm +
", deptno=" + deptno +
'}';
}
}
JDBC事务的处理
之前我们是使⽤ MySQL 的命令来操作事务。接下来我们使⽤ JDBC 来操作银⾏转账的事务。
public class Demo07 {
public static void main(String[] args) {
Connection conn = JDBCUtils.getConnection();
String sql1 = "update Account set money = money - ? where id = ? ";
String sql2 = "update Account set money = money + ? where id = ? ";
try {
conn.setAutoCommit(false);
PreparedStatement stmt1 = conn.prepareStatement(sql1);
PreparedStatement stmt2 = conn.prepareStatement(sql2);
stmt1.setInt(1,100);
stmt1.setInt(2,1);
stmt1.executeUpdate();
//出现异常 - 手动制造
// int i = 1/0;
stmt2.setInt(1,100);
stmt2.setInt(2,2);
stmt2.executeUpdate();
conn.commit();
stmt2.close();
stmt1.close();
conn.close();
} catch (SQLException throwables) {
}
}
}