JDBC
1. JDBC背景
JDBC类似pymysql
JDBC,官方定义的操作所有关系型数据库的规则,(一套接口)
本质:
代替程序员操作数据库,使用java操作
数据库厂商自己写实现类
我们只需要调JDBC的接口就ok了
多态调用
使用步骤:
在导入数据包的过程中总是报错后来,通过 select version(); 查看mysql版块与jar版本不符合,在mysql官网下载对应版主之后继续运行.
1. 导入驱动jar包 mysql-connector-java-8.25-bin.jar
1.复制mysql-connector-java-8.25-bin.jar到项目的libs目录下
2.右键-->Add As Library
2. 注册驱动
3. 获取数据库连接对象 Connection
4. 定义sql
5. 获取执行sql语句的对象 Statement
6. 执行sql,接受返回结果
7. 处理结果
8. 释放资源
初识JDBC
public class Demo01JDBC {
public static void main(String[] args) throws Exception {
//1.导入驱动jar包
//2.注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//JDK1.5版本之后现在不用注册驱动
//3.获取数据库的连接对象
//如果连接本机mysql服务器,并且服务器端口好是3306,则url可以简写,为jdbc:mysql:///python
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/python","root","123456");
//4.定义sql语句
String sql = "update classes set name = '三班' where id = '2';";
//5.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//6.执行sql
int count = stmt.executeUpdate(sql);
//7.处理结果
System.out.println(count);
//8.释放资源
stmt.close();
conn.close();
}
}
2. DriverManager:驱动管理对象
-
功能:
- 注册驱动:告诉程序该使用哪一个数据库驱动jar
static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。
写代码使用: Class.forName(“com.mysql.jdbc.Driver”);
通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException(“Can’t register driver!”);
}
}
注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。
2. 获取数据库连接:- 方法:static Connection getConnection(String url, String user, String password)
- 参数:
-
url:指定连接的路径
- 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
- 例子:jdbc:mysql://localhost:3306/db3
- 细节:如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称
- user:用户名
- password:密码
-
url:指定连接的路径
- 注册驱动:告诉程序该使用哪一个数据库驱动jar
3. Connection:数据库连接对象
- 功能:
- 获取执行sql 的对象
* **Statement createStatement()**
* **PreparedStatement prepareStatement(String sql)**
- 管理事务:
* 开启事务:**setAutoCommit(boolean autoCommit)** :调用该方法设置参数为false,即开启事务
* 提交事务:**commit()**
* 回滚事务:**rollback()**
4. Statement:执行sql的对象
-
执行sql
- boolean execute(String sql) :可以执行任意的sql 了解
- int executeUpdate(String sql) :执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句 返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。
- ResultSet executeQuery(String sql) :执行DQL(select)语句
5. ResultSet:结果集对象,封装查询结果
boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true
getXxx(参数):获取数据
Xxx:代表数据类型 如: int getInt() , String getString()
参数:
int:代表列的编号,从1开始 如: getString(1)
String:代表列名称。 如: getDouble(“balance”)
代码实现
import java.sql.*;
public class Demo05JDBC {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//1.注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象
conn = DriverManager.getConnection("jdbc:mysql:///python","root","123456");
//3.定义sql
String sql = "select * from classes";
//4.获取执行sql对象
stmt = conn.createStatement();
//5.执行sql语句
rs = stmt.executeQuery(sql);
//6.处理结果
//System.out.println(rs);
//6.1让游标向下移动一行
while (rs.next()) {
int id = rs.getInt(1);
String str = rs.getString(2);
System.out.println(id+"---"+str);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//7.释放资源
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
输出结果:
1—三班
2—三班
4—三班
JDBC 工具类
此时我们发现在我们的代码当作,有非常多重复的代码,
比如
conn = DriverManager.getConnection("jdbc:mysql:///python","root","123456");
finally {
//7.释放资源
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
那么我们可不可以给他写一个工具类,我们的目的呢是简化书写
在我们的工具类中肯定有这样的一个代码块用来关闭请求资源的。
public static void close(Statement stmt,Connection conn){
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
同时有的时候我们还会请求ResultSet的资源,在用到查询操作的时候
于是重载close方法
public static void close(ResultSet rs, Statement stmt, Connection conn){
if( rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
利用Java中的静态代码块,在类加载时会执行的特点
static {
//读取资源文件,获取值
try {
//1.创建Properties集合类
Properties pro = new Properties();
//2.加载文件
//获取src路径下的文件方式-->ClassLoader 类加载器
ClassLoader classLoader = Demo02JDBCUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
pro.load(new FileReader("C:\\Users\\86157\\Desktop\\javatest\\java基础\\12JDBC\\jdbc.properties"));
//4. 注册驱动
//Class.forName(driver);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
这是上图中,URL res = classLoader.getResource(“jdbc.properties”);加载的配置文件
文件内容很容易理解,利用了Properties这个集合类来读取文件内容
url=jdbc:mysql:///python
user=root
password=123456
driver=com.mysql.jdbc.Driver
此时呢,pro读取了配置文件中的数据,通过get方法,将它赋值给我们设置的静态变量
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
对了,我们在static外面还要设置静态变量
//静态代码块,配置文件只需要读取一次
private static String url;
private static String user;
private static String password;
private static String driver;
此时我们在定义一个getConnection的方法,来获取Connection这个类,进而通过conn来获取执行sql的对象
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
现在我们的工具类基本上是完成了
整体写一下
package Demo02封装类;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
/*
简化书写
*/
public class Demo02JDBCUtils {
//静态代码块,配置文件只需要读取一次
private static String url;
private static String user;
private static String password;
private static String driver;
static {
//读取资源文件,获取值
try {
//1.创建Properties集合类
Properties pro = new Properties();
//2.加载文件
//获取src路径下的文件方式-->ClassLoader 类加载器
ClassLoader classLoader = Demo02JDBCUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
pro.load(new FileReader("C:\\Users\\86157\\Desktop\\javatest\\java基础\\12JDBC\\jdbc.properties"));
//3.获取数据,赋值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//4. 注册驱动
//Class.forName(driver);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
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 e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(ResultSet rs, Statement stmt, Connection conn){
if( rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
封装类
现在我们有一个需求,希望把数据库中的对象封装在java的类中,以便于后续来对他进行处理
如图这是我们的商品
class goods{
private int id;
private String name;
private String cate_name;
private String brand_name;
private int price;
@Override
public String toString() {
return "goods{" +
"id=" + id +
", name='" + name + '\'' +
", cate_name='" + cate_name + '\'' +
", brand_name='" + brand_name + '\'' +
", price=" + price +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCate_name() {
return cate_name;
}
public void setCate_name(String cate_name) {
this.cate_name = cate_name;
}
public String getBrand_name() {
return brand_name;
}
public void setBrand_name(String brand_name) {
this.brand_name = brand_name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
定义一个商品类,重写他的toString方法,同时设置get和set
接下来我们开始写代码
首先我们要获取获取连接,用到了刚才写的工具类
conn = Demo02JDBCUtils.getConnection();
定义一个sql语句
String sql = "select * from goods";
获取执行sql的对象
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
goods goods = null;
goodss = new ArrayList<goods>();
//6.变量结果集,封装对象
while (rs.next()) {
//获取数据
int id = rs.getInt("id");
String name = rs.getString("name");
String cate_name = rs.getString("cate_name");
String brand_name = rs.getString("brand_name");
int price = rs.getInt("price");
//创建goods对象,并赋值
goods = new goods();
goods.setId(id);
goods.setPrice(price);
goods.setName(name);
goods.setCate_name(cate_name);
goods.setBrand_name(brand_name);
goodss.add(goods);
}
遍历这个集合
public static void main(String[] args) {
List<goods> ls = new Demo01Test().findAll();
for(goods g : ls){
System.out.println(g);
}
}
goods{id=1, name='r510vc 15.6英寸笔记本', cate_name='笔记本', brand_name='华硕', price=3399}
goods{id=2, name='y400n 14.0英寸笔记本电脑', cate_name='笔记本', brand_name='联想', price=4999}
goods{id=3, name='g150th 15.6英寸游戏本', cate_name='游戏本', brand_name='雷神', price=8499}
goods{id=4, name='x550cc 15.6英寸笔记本', cate_name='笔记本', brand_name='华硕', price=2799}
goods{id=5, name='x240 超极本', cate_name='超级本', brand_name='联想', price=4880}
goods{id=6, name='u330p 13.3英寸超极本', cate_name='超级本', brand_name='联想', price=4299}
goods{id=7, name='svp13226scb 触控超极本', cate_name='超级本', brand_name='索尼', price=7999}
goods{id=8, name='ipad mini 7.9英寸平板电脑', cate_name='平板电脑', brand_name='苹果', price=1998}
goods{id=9, name='ipad air 9.7英寸平板电脑', cate_name='平板电脑', brand_name='苹果', price=3388}
goods{id=10, name='ipad mini 配备 retina 显示屏', cate_name='平板电脑', brand_name='苹果', price=2788}
goods{id=11, name='ideacentre c340 20英寸一体电脑 ', cate_name='台式机', brand_name='联想', price=3499}
goods{id=12, name='vostro 3800-r1206 台式电脑', cate_name='台式机', brand_name='戴尔', price=2899}
goods{id=13, name='imac me086ch/a 21.5英寸一体电脑', cate_name='台式机', brand_name='苹果', price=9188}
goods{id=14, name='at7-7414lp 台式电脑 linux )', cate_name='台式机', brand_name='宏碁', price=3699}
goods{id=15, name='z220sff f4f06pa工作站', cate_name='服务器/工作站', brand_name='惠普', price=4288}
goods{id=16, name='poweredge ii服务器', cate_name='服务器/工作站', brand_name='戴尔', price=5388}
goods{id=17, name='mac pro专业级台式电脑', cate_name='服务器/工作站', brand_name='苹果', price=28888}
goods{id=18, name='hmz-t3w 头戴显示设备', cate_name='笔记本配件', brand_name='索尼', price=6999}
goods{id=19, name='商务双肩背包', cate_name='笔记本配件', brand_name='索尼', price=99}
goods{id=20, name='x3250 m4机架式服务器', cate_name='服务器/工作站', brand_name='ibm', price=6888}
goods{id=21, name='商务双肩背包', cate_name='笔记本配件', brand_name='索尼', price=99}
输出结果
事务
事物4大特性简称ACID
保证付款方付款收款方收款
一个很好的处理事务系统,必须具备这些标准特性:
原子性( atomicity)
一个必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性
一致性(consistency)
从一个一致性的状态转换到另一个一致性的状态。 (在前面的例子中,一致性确保了,即使在执行第三、四条语句之间时系统崩溃,支票账户中也不会损失200美元,因为事务最终没有提交,所以事务中所做的修改也不会保存到拟文件中。 )
隔离性(isolation)
通常来说,一个事务所做的修改在最终提交以前,对事务是不可见的。 (在前面的例子中,当执行完第三条语句、第四条语句还未开始时,此时有另外的一个账户汇总程序开始运行,则其看到支票账户的余额并没有被减去200美元。 )
持久性(durability)
一旦事务提交,则其所做的修改会永久保存到数据。 (此时即使崩溃系统,修改的数据也不会丢失。 )
操作:
1. 开启事务
2. 提交事务
3. 回滚事务
3. 使用Connection对象来管理事务
* 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
* 在执行sql之前开启事务
* 提交事务:commit()
* 当所有sql都执行完提交事务
* 回滚事务:rollback()
* 在catch中回滚事务
public class Demo01事务 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;
try {
//获取连接
conn = Demo02JDBCUtils.getConnection();
//定义sql加钱
String sqla = "update user set password = password - ? where id = ?";
//定义sql减钱
String sqlb = "update user set password = password + ? where id = ?";
//获取执行对象
pstmt1 = conn.prepareStatement(sqla);
pstmt2 = conn.prepareStatement(sqlb);
//设置参数
pstmt1.setDouble(1,500);
pstmt1.setInt(2,1);
pstmt2.setDouble(1,500);
pstmt2.setInt(2,2);
//开启事务
conn.setAutoCommit(false);
//更新操作,执行sql
pstmt1.executeUpdate();
int i = 3/0;
pstmt2.executeUpdate();
//事务提交
conn.commit();
} catch (SQLException e) {
//事务的回滚
try {
if(conn!=null) {
conn.rollback();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}finally {
Demo02JDBCUtils.close(pstmt2,conn);
Demo02JDBCUtils.close(pstmt1,null);
}
}
}
这样就完成了一个事务