JDBC概念
什么是JDBC:Java DataBase Connectivity 使用Java语言连接数据库的技术。
本质:是官方定义的操作数据库的一套规范,规则,都是接口。各个数据库厂商去实现这套接口,提供对应的数据库驱动jar包。我们可以使用这个驱动jar包,来完成连接数据库操作数据库的功能。
快速入门
步骤:
-
添加jar包到工程中,添加到工程的lib文件夹下,右键选择Bulib puth 中的Add…(eclipse中) (Add as Library(idea中))
-
public class JDBCDemo { public static void main(String[] args) throws Exception { //2注册驱动 com.mysql.jdbc.Driver.class Class.forName("com.mysql.jdbc.Driver");// 通过该类的路径反射生成该类的字节码对象 //3.获取数据库的连接对象 Connection Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/java31", "root", "root"); //4.准备sql语句 String sql = "update account set balance = 20000 where username = '张三'"; //5.获取执行sql语句的对象 Statement Statement createStatement = connection.createStatement(); //6.通过Statement对象执行sql语句 int count = createStatement.executeUpdate(sql); //如果>0就代表执行成功 if(count > 0) { System.out.println("成功"); }else { System.out.println("失败"); } //打开的连接对象关闭,先开后关,后开先关. createStatement.close(); connection.close(); } }
介绍JDBC快速入门用到的包和类
包
java.sql
所有与JDBC访问数据库相关的类和接口。javax.sql
用到数据库连接池 数据库的扩展包,提供数据库操作额外的功能,如:连接池。
类,接口
DrierManager
驱动管理 注册驱动,还有获取数据库连接对象(类)Connection
连接对象,用于创建执行sql对象 Statement、PreparedStatement对象Statement
sql语句执行对象,用于将sql语句发送给数据库服务器PreparedStatement
sql语句执行对象,是Statement的子接口ResultSet
用于封装从数据库查询出来的结果值
DrierManager类
-
从JDBC3开始,可以不用注册驱动直接使用。Class.forName();可以省略
-
驱动类路径 com.mysql.jdbc.Driver
-
Connection
getConnection(url,user,password)
:可以获取到数据库的连接对象 -
Connection
getConnection(url,Properties info)
:通过连接字符串和属性对象 获取数据连接对象 -
user :登录数据库用户名
-
password :登录数据库的密码
-
url:连接数据库的路径 对于mysql而言是:jdbc:mysql://服务器ip地址:端口号3306/数据库名称[?参数名 = 参数值]
-
jdbc:mysql://服务器ip地址:端口号3306/数据库名称[?参数名 = 参数值]; 如果数据库服务器是在本地中,可以省略掉ip地址和端口号–> jdbc:mysql:///数据库名称[?参数名 = 参数值]
如果数据传输时引发类乱码,后面可以使用参数 charcaterEncoding=utf8–>
jdbc:mysql:///数据库名称?charcaterEncoding=utf8
Connection接口
作用:连接数据库,它是一个接口,由具体的厂商来提供具体的实现类,代表的是一个连接对象
- Statement
createStatement()
创建一个sql执行对象 - PrepareStatement
preparedStatement()
创建一个sql预处理对象
Statement接口
作用:用来执行sql语句,本质是把sql语句发送给数据库服务器
- int
executeUpdate(sql)
:用于把sql语句发送给服务器,执行增删改操作。返回值int 影响数据库的记录数(行数) - ResultSet
executeQuery(String sql)
:用于把sql语句发送给服务器,执行查询操作,返回值ResultSet 查询返回的结果集
PreparedStatement
-
执行sq的l对象
-
会防止一些sql非法注入问题,在拼接sql语句时,可能会造成安全性问题。如:
" select * from account where username like '% " +username + " % ’ and balance = ’ " + balance + " ’ + " or 1 = 1 "
此时出现 " or 1=1 " 非法拼接问题。
使用预编译的sql,参数使用
?
作为占位符操作:
-
在sql语句中涉及到参数时使用
?
替代具体的数据 如: select * from user where username = ? and password = ? -
使用连接对象执行sql语句获取预编译对象 connection.preparedStatement(String sql)
-
给?赋值:
使用方法:setXxx(索引下标,?对应的实际值)
-
使用预编译对象执行sql,获取返回的结果集值—>preparedStatement.executeQuery();
-
处理结果,释放资源。
-
释放资源
- 需要释放的资源对象:ResultSet对象,Statement对象,Connection对象
- 释放的顺序:先开后关,后开先关 ResultSet–>Statement–>Connection
- 释放资源:使用finally语句块,一定会被加载到。不能单独使用,搭配try语句块。
常用数据库数据类型和Java类型对照
sql | jdbc方法 | Java |
---|---|---|
int | getInt() | int |
bigInt | getLong() | long |
bit | getBoolean() | boolean |
varchar | getString() | String |
date/time/TimeStamp | getDate/getTime/getTimeStamp | java.util.Date/java.sql.Time/java.sql.Timestamp |
备注:java.sql.Date/Time/TimeStamp (时间戳) 三个共同的父类时–>java.util.Date
数据库工具类 DBUtil
// 数据库工具类
public class DBUtil {
// 定义四个常量值
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql:///java31?characterEncoding=utf8";
private static final String USER = "root";
private static final String PASSWORD = "root";
// 定义JDBC常用类和接口
private static Connection con = null;
private static Statement st = null;
private static PreparedStatement ps = null;
private static ResultSet set = null;
static {
try {
Class.forName(DRIVER);
con = DriverManager.getConnection(URL, USER, PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
}
// 针对查询的功能
public static ResultSet select(String sql,Object[] args) {
//String sql2 = "select * from account where u_name = ? and password = ?";
try {
// 获取预处理对象
ps = con.prepareStatement(sql);
// 使用sql语句中的占位符 ?
// 遍历数组
// 占位符 在sql中是有前后顺序的 u_name对应的问号 索引是 1 password对应的问号就是2
for (int i = 0; i < args.length; i++) {
// 把问号提换成具体的数据
ps.setObject(i+1, args[i]);
}
// 执行sql语句 获取结果值
set = ps.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return set;
}
// 针对更新的功能 insert update delete executeUpdate()
public static int update(String sql,Object[] args) {
// 获取预处理对象
// 定义一个变量 用来记录印象数据库表的行数
int count = 0;
try {
ps = con.prepareStatement(sql);
// 使用sql语句中的占位符 ?
// 遍历数组
// 占位符 在sql中是有前后顺序的 u_name对应的问号 索引是 1 password对应的问号就是2
for (int i = 0; i < args.length; i++) {
// 把问号提换成具体的数据
ps.setObject(i+1, args[i]);
}
// 执行sql语句 获取结果值
count = ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 返回给调用处
return count;
}
// 关闭连接的方法
public static void closeAll() {
// 关闭时 先关闭ResultSet
if (set != null) {
try {
set.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
表与类的关系
-
整个表可以看做成一个类
-
表的每一行称之为一条记录,可以看做成一个类的实例
-
表中的每一列可以看做成实例对象中的每个属性。
-
实体类、model类需要和数据库中的类进行一一映射
- 表中的列名和model类中的属性名保持一致
- 表中的列字段数据类型和model类中的属性数据类型保持一致
JDBC事务
事务:一个包含多个步骤或业务操作。如果这个业务或者多个步骤被事务管理,则这多个步骤,要么同时成功,要么回滚(多个步骤同时执行失败),这多个步骤是一个整体,不可分割的
操作:
mysql中
- 开启事务:start transaction
- 提交事务:commit
- 回滚事务:rollback
JDBC中,
需要使用Connection对象来管理事务
- 开启事务:
setAutoCommit(boolean autoCommit);
:执行该方法里面传入false值,手动开启事务 --> 在所有sql语句执行之前开启事务 - 提交事务:
commit();
方法 -->当所有的sql语句执行完毕才提交事务 - 回滚事务:
rollback();
方法 -->当事务中发生异常时回滚事务,回滚事务放在catch语句中
实例:以银行转账为例,让张三给李四转账10000
public class TransformTest {
private static PreparedStatement ps1 = null;
private static PreparedStatement ps2 = null;
public static void main(String[] args) {
//transform01();
transform02();
}
//含有事务的方法
public static void transform02(){
//让张三的钱减少10000
//让李四的钱增减10000
//定义实现转账的两条sql语句
double money = 10000;
String username01 = "张三";
String username02 = "李四";
String sql1 = "update account set balance = balance - ? where username = ?";
String sql2 = "update account set balance = balance + ? where username = ?";
//使用Connection对象手动开启事务 set
Connection connection = DBUtil.getConnection();
try {
connection.setAutoCommit(false);
//先让张三的钱-10000
//通过connection获取预处理对象
ps1 = connection.prepareStatement(sql1);
ps1.setDouble(1,money);
ps1.setString(2,username01);
//执行sql语句
int count1 = ps1.executeUpdate();
//制造一个异常
int i = 1 / 0;
//先让张三的钱-10000
//通过connection获取预处理对象
ps2 = connection.prepareStatement(sql2);
ps2.setDouble(1,money);
ps2.setString(2,username02);
//执行sql语句
int count2 = ps2.executeUpdate();
//提交事务
connection.commit();
System.out.println("转账成功");
} catch (Exception e) {
System.out.println("转账失败");
//回滚事务
try {
connection.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
e.printStackTrace();
}finally {
//把打开的连接对象释放掉
try {
ps1.close();
ps2.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//不带事务的转账
public static void transform01(){
//让张三的钱减少10000
//让李四的钱增减10000
//定义实现转账的两条sql语句
double money = 10000;
String username01 = "张三";
String username02 = "李四";
String sql1 = "update account set balance = balance - ? where username = ?";
String sql2 = "update account set balance = balance + ? where username = ?";
//张三减少10000
int count01 = DBUtil.update(sql1, new Object[]{money, username01});
//制造一个程序异常
int i = 1/0;
//李四增加10000
int count02 = DBUtil.update(sql2, new Object[]{money, username02});
if (count01 > 0 && count02 > 0){
System.out.println("转账成功");
}else {
System.out.println("转账失败");
}
//释放资源
DBUtil.closeAll();
}
}
。。