Java-Jdbc进阶

JDBC进阶

PreparedStatement

预处理语句,这个接口继承了Statement接口

1.解决字符串拼接的问题

2.解决sql注入问题

3.让效率更高一点

实现步骤

前面连接数据库都是一样的步骤

在拿到语句对象的时候就使用SQL

将Statement st = conn.createStatement();

替换成PreparedStatement st = conn.prepareStatement(sql);//预编译sql
在执行的时候不需要传sql;

1
2
3
4
5
String sql = "select * from login where username=? and password=?";
PreparedStatement pStatement = conn.prepareStatement(sql);
pStatement.setString(1, username);
pStatement.setString(2, pwd);
ResultSet set = pStatement.executeQuery();

Demo

使用两种方式来判断登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.ifueen.homework.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.ifueen.classtest.util.JDBCUtil;
import com.ifueen.classtest.util.JDBCUtilDataSource;
import com.ifueen.homework.dao.LoginDao;
import com.sun.javafx.binding.Logging;

public class LoginDaoImpl implements LoginDao{

/**
* 第一种判断登录的方式
*/
@Override
public void login(String username, String pwd) {
// TODO Auto-generated method stub
Connection conn = JDBCUtilDataSource.getinstance().getconn();
try {
Statement statement = conn.createStatement();
String sql = "select * from login";
ResultSet rs = statement.executeQuery(sql);
if (rs.next()) {
if (!rs.getString("username").equals(username)) {
System.out.println("你有这个账户吗?嗯?弟弟");
}else{
if (rs.getString("username").equals(username) && rs.getString("password").equals(pwd)) {
System.out.println("登录成功");
}else{
System.out.println("密码都记不住吗弟弟?");
}
}
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

/**
* 第二种
* 使用prepareStatement来进行加载,避免了sql注入问题
*/
@Override
public void login2(String username, String pwd) {
// TODO Auto-generated method stub
Connection conn = JDBCUtilDataSource.getinstance().getconn();
try {
String sql = "select * from login where username=? and password=?";
PreparedStatement pStatement = conn.prepareStatement(sql);
pStatement.setString(1, username);
pStatement.setString(2, pwd);
ResultSet set = pStatement.executeQuery();
if (set.next()) {
if (set.getString("username").equals(username) && set.getString("password").equals(pwd))
System.out.println("登录成功");
}else{
System.out.println("密码都记不住吗弟弟?");
}

JDBCUtil.getinstance().getclose(pStatement, conn);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

😊事务

什么是事务

事务: 程序里面的一组操作,要不都成功,要不都失败;

事务示例:
银行转帐功能: bank / money
小冯和小红:
小冯 : 10000块钱 小红 : 0块钱

转账:小冯要给小红转1000块钱
分析:转钱需要提供两条sql,但是程序员也会出错,比较代码写错了.

如果在扣款时出错,那么小冯的余额扣除了但是小红却没有收到,所以不合理

这个时候就需要用到事务操作了

事务的操作:先定义开始一个事务,然后对数据作修改操作,这时如果提交(commit),这些修改就永久地保存下来,如果回退(rollback),数据库管理系统将放弃您所作的所有修改而回到开始事务时的状态。

事物的四大特性(面试题)

事物四大特性:ACID

原子性:一组操作不可分割

一致性:操作前后需要一直

隔离性:并发编程的时候,多个线程之间的操作不会相会影响

持久性:将内存中的数据持久化到磁盘

Demo

利用事务实现的转账功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.ifueen.homework.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.ifueen.classtest.util.JDBCUtilDataSource;
import com.ifueen.homework.dao.Transfer;
import com.sun.org.apache.bcel.internal.generic.Select;

public class TransferDaoImpl implements Transfer{

/**
* 查询账户余额
*/
@Override
public double select(String name) {
Double b = null;
// TODO Auto-generated method stub
Connection conn = JDBCUtilDataSource.getinstance().getconn();
String sql = "select balance from transfer where name = ?";
try {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
while(rs.next()){
b = rs.getDouble("balance");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return b;
}


/**
* 转账功能
*/
@Override
public void transfer(String name, String name2, double money) {
// TODO Auto-generated method stub
Connection conn = JDBCUtilDataSource.getinstance().getconn();
try {
//设置事务的自动提交为false,即不自动提交
conn.setAutoCommit(false);
String sql = "update transfer set balance= ? where name = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setDouble(1, select(name)-money);
ps.setString(2, name);
ps.executeUpdate();
//测试意外情况
//System.out.println(1/0);
//另一个账户增加
String sql1 = "update transfer set balance= ? where name = ?";
PreparedStatement ps1 = conn.prepareStatement(sql1);
ps1.setDouble(1, select(name2)+money);
ps1.setString(2, name2);
ps1.executeUpdate();

//完成操作提交事务
conn.commit();
JDBCUtilDataSource.getinstance().getclose(ps,conn);
JDBCUtilDataSource.getinstance().getclose(ps1,conn);
System.out.println("转账成功啦");
} catch (SQLException e) {
// TODO Auto-generated catch block
try {
//设置事务的自动回滚
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}

注意!MySQL中,InnoDB支持外键.支持事务,MyISAM不支持外键,不支持事务

使用JDBC拿到主键

为什么需要拿到Id?

现在我们插入的一条数据,但是并不知道该数据的id是多少, 而我们有时候操作,需要这个id.

比如我们向product表插入一条数据,它的数量为200,但是product表里面并没有表示数量的字段,而product_store表里面含有storeNum,所有我们应该在插入数据之后,同时需要插入一条数据到product_store表里面; – 这时候我们就需要拿到product表里新插入的id;

拿到主键的方法:

1
2
3
4
5
6
7
8
9
10
11
Connection conn = JDBCUtilDataSource.getinstance().getconn();
String sql = "insert into student (name,age) value (?,?)";
PreparedStatement ps = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
ps.setString(1, name);
ps.setInt(2, age);
ps.execute();
//拿到主键的集合
ResultSet rs = ps.getGeneratedKeys();
while (rs.next()) {
System.out.println(rs.getLong(1));
}

连接池

为什么要连接池?

每次请求都会创建一个connection,因此会浪费资源(内存),当同时1000人访问的时候,那就会占用很多资源,因此很浪费时间和容器操作系统崩溃

认识连接池

节约内存资源 维护连接对象的生命周期
最开始的时候就创建一些连接对象放到连接池中 请求来了可以直接在连接池中获取连接 操作数据库

操作完成以后 释放连接 回到连接池 等待下一次被请求使用
初始的时候 创建了一些连接 最小连接数 请求并发的时候 创建更多的连接 最大连接

常见的连接池

dbcp(spring集成)

c3p0

druid(常用)

使用dbcp连接池

注意:在使用连接池之前需要导入相应的包

1
2
3
4
Properties prop =new Properties();
prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"))
DataSource ds = BasicDataSourceFactory.createDataSource(prop);
Connection conn=ds.getConnection();
❤赏点钱让我买杯快乐水8❤