文章目录
1、JDBC连接数据的步骤
- 加载驱动
- 根据URL、用户名和密码建立连接
- 创建处理快,有静态处理快(Statement)和预处理块(PreparedStatement)
- 执行数据库语句
- 处理得到的结果
- 释放资源
2、连接
2.1、准备工作
-
导入驱动包
-
构建路径 build path
-
测试用户是否正确登录
2.2、建立连接
- 连接字符串
- 加载驱动: oracle.jdbc.driver.OracleDriver
- URL:jdbc:oracle:thin:@db 服务器地址:端口:实例
- 连接URL:jdbc:oracle:thin:@localhost:1521:orcl
- 用户名和密码:SCOTT TIGER
- 编写测试类
- 加载驱动
- 建立连接:Connection con =DriverManager.getConnection(“jdbc:oracle:thin:@locahost:1521:orcl”,“scott”,“tiger”)
3、处理块
3.1、静态处理块
Statement 是 Java 执行数据库操作的一个重要接口,用于在已经建立数据库连接的基础上,向数据库发送要执行的 SQL 语句。Statement 对象,用于执行不带参数的简单 SQL 语句。 执行静态 SQL 语句并返回它所生成结果的对象。
特点:
- 处理 不变的静态的 sql 语句
- 优点: 直接查看sql ,方便处理错误
- 缺点:性能不高、拼接 sql 麻烦、可能存在 sql 注入
方法的使用:
- 增删改使用executeUpdate( )函数,返回一个int值,表示影响的行数。
- 查询使用executeQurey()函数,返回一个ResultSet对象,该对象中封装着查询的信息
- ResultSet对象必须先试用
.next()
函数判断是否有值,才能使用getInt/getString/getBoolean等方法获取到值(可以简单的使用getObject()方法获取到任意类型的数据),如果不使用.next()
函数判断是否有值就直接获取值,则会出现java.sql.SQLException: 未调用 ResultSet.next异常。
- ResultSet对象必须先试用
代码:
/*
* JDBC基本流程:
* 1.加载驱动 (选择哪一个数据库)
* 2.获取连接 (与数据库连接上)
* 3.准备sql
* 4.获取处理块(打包发送)
* 5.接收结果集
* 6.处理结果数据
* 7.关闭
*/
public class Demo01JDBC {
public static void main(String[] args) throws Exception {
//1.加载驱动 (选择哪一个数据库)
Class.forName("oracle.jdbc.OracleDriver");
//2.获取连接 (与数据库连接上)
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "SCOTT", "TIGER");
//3.准备sql
String sql = "select * from dept";
//4.获取处理块(打包发送)
Statement sta = conn.createStatement();
//5.接收结果集
ResultSet result = sta.executeQuery(sql);
//6.处理结果数据
while(result.next()){
int deptno = result.getInt("deptno");
String dname = result.getString("dname");
String loc = result.getString("loc");
System.out.println(deptno+"--->:"+dname+"--->"+loc);
}
//7.关闭资源
result.close();
sta.close();
conn.close();
}
}
注意:
- 释放资源时,先打开的后关闭。
**优化:**可以将加载数据库驱动和获取数据库连接的操作放在静态代码块中,类只需要加载一次即可,不需要重复加载。
public class Demo02JDBC {
// 声明连接数据库的对象
public static Connection conn;
static{
// 加载数据库
try {
Class.forName("oracle.jdbc.OracleDriver");
// 和数据库建立连接
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "SCOTT", "TIGER");
// 准备sql语句
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args)throws Exception {
// 准备sql语句
String sql = "select * from dept where deptno=10";
// 获取处理块
Statement sta = conn.createStatement();
// 执行sql语句
ResultSet result = sta.executeQuery(sql);
// 处理数据
while(result.next()){
int deptno = result.getInt(1);
String dname = result.getString(2);
String loc = result.getString(3);
System.out.println(deptno+"--->"+dname+"--->"+loc);
}
//7.关闭资源
result.close();
sta.close();
conn.close();
}
}
3.2、预处理块
PreparedStatement 接口继承了 Statement,并与之在两方面有所不同:有人主张,在 JDBC 应用中,如果你已经是稍有水平开发者,你就应该始终以PreparedStatement 代替 Statement.也就是说,在任何时候都不要使用 Statement。
由于 PreparedStatement 对象已预编译过,所以其执行速度要快于 Statement 对象。因此,多次执行的 SQL 语句经常创建为 PreparedStatement 对象,以提高效率。
特点:
- 处理 不变的静态的 sql 语句 |可变的 sql 语句 带 ? 的 sql
- 优点:性能高,方便编写sql 不存在sql注入 安全
- 缺点:不能直接打印sql语句 不方便处理错误
例如要查询的sql语句为:select * from users where name=? and pwd=?,要查询的内容使用?做占位符。
使用的方法:
- 设置值:为sql语句中的?设置值**setInt(字段名|字段的序号)/setString()/setBolean()等设置响应的值,也可以简单的使用setObject(字段名|字段的序号)**设置任意类型的值。
- 获取值:从获取到的结果集中拿数据,使用函数getInt(字段名|字段的序号)/getSting()/getBoolean(),也可以简单的使用**getObject(字段名|字段的序号)**获取任意类型的值。
- 序号是从1开始的。
代码:
/**
* 使用预处理块查询数据库的数据
*
*/
public class Demo05 {
public static void main(String[] args) throws Exception{
// 加载数据库驱动
Class.forName("oracle.jdbc.OracleDriver");
// 获取数据库的连接
Connection conn =DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "SCOTT", "TIGER");
// 准备sql语句(根据用户名和密码查询用户信息)
String sql = "select * from users where name=? and pwd=?";
// 获取预处理块,对查询数据的sql语句进行预编译
PreparedStatement ps = conn.prepareStatement(sql);
// 为sql语句设置值
ps.setObject(1, "张万里");
ps.setObject(2, "1314");
// 执行sql语句
ResultSet result = ps.executeQuery();
// 处理获取到的数据
while(result.next()){
System.out.println("id"+"\tname"+"\tpwd"+"\tbirthday");
System.out.println(result.getObject(1)+"\t"+result.getObject(2)+"\t"+result.getObject(3)+"\t"+result.getObject(4));
}
}
}
3.3、使用db.properties配置文件
db.properties的配置文件
driver=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
uname=SCOTT
pwd=TIGER
使用配置文件获取数据库的连接:
/**
* 数据库工具类,获取数据库的Connection连接对象
*/
public class DBUtil {
// 获取资源配置文件对象
private static Properties p = null;
static{
p = new Properties();
try {
// 获取配置文件
p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
} catch (IOException e) {
System.out.println("加载配置文件失败");
e.printStackTrace();
}
try {
// 加载数据库
Class.forName(p.getProperty("driver"));
} catch (ClassNotFoundException e) {
System.out.println("加载数据库失败");
e.printStackTrace();
}
}
/**
* 获取数据库的连接
*/
public static Connection getConnection() throws SQLException{
Connection conn = null;
conn = DriverManager.getConnection(p.getProperty("url"), p.getProperty("uname"), p.getProperty("pwd"));
return conn;
}
3.3.1、模拟注册账户
使用上述的工具类
/**
* 注册
*/
public static boolean login(){
Scanner sc = new Scanner(System.in);
System.out.print("用户名:");
String name = sc.next();
System.out.print("密码:");
String pwd = sc.next();
Connection conn = null;
try {
// 获取数据库的连接
conn = DBUtil.getConnection();
} catch (SQLException e) {
System.out.println("连接数据库失败");
e.printStackTrace();
}
boolean flag = true;
// 循环检测要注册的账户是否存在
while(flag){
if(check(name, pwd,conn)){
System.out.println("该用户已经存在,请重输入!");
System.out.print("用户名:");
name = sc.next();
System.out.print("密码:");
pwd = sc.next();
}else{
flag = false;
}
}
// 准备sql语句
String sql2 = "insert into users values(quecreate_users_id.nextval,?,?)";
PreparedStatement ps = null;
// 操作数据库影响的行数
int rows = 0;
try {
ps = conn.prepareStatement(sql2);
ps.setObject(1, name);
ps.setObject(2, pwd);
// 返回影响的行数
rows = ps.executeUpdate();
} catch (SQLException e) {
System.out.println("向数据库插入数据异常");
e.printStackTrace();
}finally{
// 关闭资源(自己封装的方法)
DBUtil.close(ps, conn);
}
// 更改标志位
if(rows>0){
System.out.println("注册成功");
return true;
}else{
System.out.println("注册失败");
return false;
}
}
3.3.2、模拟登录账户
/**
* 登录
*/
public static void enter(){
if(user!=null){
System.out.println("不要重复登录!");
start();
return;
}
Scanner sc = new Scanner(System.in);
System.out.print("用户名:");
String name = sc.next();
System.out.print("密码:");
String pwd = sc.next();
// 连接数据库
Connection conn = null;
ResultSet result = null;
PreparedStatement sta = null;
try {
conn = DBUtil.getConnection();
boolean flag = true;
while(flag){
// 准备sql语句
String sql = "select * from users where name=? and pwd=?";
sta = conn.prepareStatement(sql);
sta.setObject(1, name);
sta.setObject(2, pwd);
// 执行sql语句
result = sta.executeQuery();
if(result.next()){
System.out.println("登录成功");
flag = false;
}else{
System.out.println("用户名或密码错误,请重新输入完成登录");
System.out.print("用户名:");
name = sc.next();
System.out.print("密码:");
pwd = sc.next();
}
}
} catch (SQLException e) {
System.out.println("登录异常");
e.printStackTrace();
}finally {
DBUtil.close(result, sta, conn);
}
user = new User(name,pwd);
start();
}
3.3.3、模拟修改密码
/**
* 修改密码
*/
public static void modify(){
if(user == null){
System.out.println("登录后才能修改数据");
start();
return;
}
Scanner sc = new Scanner(System.in);
// 检测两次输入的密码
boolean flag = true;
String newpwd = null;
while(flag){
System.out.print("新密码:");
newpwd = sc.next();
System.out.println("请再次输入新密码:");
String againPwd = sc.next();
if(!newpwd.equals(againPwd)){
System.out.println("两次密码不一致,请重新输入");
}else{
flag = false;
}
}
Connection conn = null;
PreparedStatement sta = null;
// 执行sql影响的记录数
int rows = 0;
try {
// 获取数据库的连接
conn = DBUtil.getConnection();
// 准备sql语句
String sql = "update users set pwd=? where name=?";
sta = conn.prepareStatement(sql);
sta.setObject(1, newpwd);
sta.setObject(2, user.getName());
// 执行sql语句
rows = sta.executeUpdate();
} catch (SQLException e) {
System.out.println("操作数据库失败");
e.printStackTrace();
}
// 判断时是否修改成功
if(rows > 0){
System.out.println("修改密码成功!");
user = null;
start();
}
}
3.3.4、模拟注销用户
/**
* 注销用户
*/
public static void delete(){
if(user == null){
System.out.println("请先登录!");
start();
}
Connection conn = null;
PreparedStatement sta = null;
// 数据库操作影响的行
int rows =0;
try {
// 连接数据库
conn = DBUtil.getConnection();
// 准备sql语句
String sql = "delete from users where name=? and pwd=?";
sta = conn.prepareStatement(sql);
// 设置参数
sta.setObject(1, user.getName());
sta.setObject(2, user.getPwd());
// 执行删除操作
rows = sta.executeUpdate();
} catch (SQLException e) {
System.out.println("注销用户异常");
e.printStackTrace();
}finally {
DBUtil.close(sta, conn);
}
// 判断是否删除数据成功
if(rows > 0){
System.out.println("注销账户成功!");
user = null;
start();
return;
}
}
4、事务问题
当涉及到事务问题时可以使用的方法有:
- 使用**conn.setAutoCommit(false)**方法设置手动提交事务
- 使用方法**conn.commit()**提交事务
- 使用方法**conn.rollback()**回滚事务。
模拟转账:
/**
* 模拟转账
*/
public static void change(){
Connection conn = null;
PreparedStatement sta = null;
try {
// 获取数据库的连接
conn = DBUtil.getConnection();
// 设置手动提交
conn.setAutoCommit(false);
// 准备sql语句
String sql1 = "update emp set sal = 2000 where empno = 7369";
sta = conn.prepareStatement(sql1);
int rows1 = sta.executeUpdate();
// 准备sql语句
String sql2 = "update emp set sal = 10000 where empno = 7839";
sta = conn.prepareStatement(sql2);
int rows2 = sta.executeUpdate();
if(rows1 > 0 && rows2 > 0){
// 提交事务
conn.commit();
System.out.println("修改工资成功");
}else{
// 事务回滚
conn.rollback();
System.out.println("修改工资失败");
}
} catch (SQLException e) {
System.out.println("修改工资异常");
e.printStackTrace();
}finally{
// 关闭资源
DBUtil.close(sta, conn);
}
}