一、什么是JDBC
JDBC是一套面向对象的应用编程接口,它制定了统一的访问各类关系数据库的标准接口,为各个数据库厂商提供了标准接口的实现。通过使用JDBC技术,开发人员可以用纯java和标准的SQL语句编写完整的数据库应用程序。
一下操作基于此表:
-- auto-generated definition
create table user(
id int auto_increment primary key,
name char(10) not null,
gender tinyint default 0 not null,
age tinyint default 0 not null,
nationality char(10) null,
constraint user_name_uindex
unique (name)
);
二、连接步骤
代码
public class JDBCTest {
public static void main(String[] args) {
final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
final String URL = "jdbc:mysql://localhost:3306/数据库名称?useSSL=false&serverTimezone=UTC";
final String USERNAME = "root";
final String PASSWORD = "123"; // 数据库密码(换成你自己的)
String sql = "select * from user";
try {
// 1. 加载mysql驱动
Class.forName(JDBC_DRIVER);
// 2. 获取连接
Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
// 3. 获取命令对象
Statement statement = conn.createStatement();
// 4. 执行sql,并获取结果
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
int id = rSet.getInt("id");
String name = rSet.getString("name");
String gender = rSet.getString("gender");
int age = rSet.getInt("age");
String nationality = rSet.getString("nationality");
System.out.println(id + "--" + name + "--" + gender + "--" + age + "--" + nationality);
}
// 5. 关闭连接
conn.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
详细步骤
1. 加载驱动程序
注:mysql驱动jar包版本最好和mysql版本一致
final String driver = "com.mysql.jdbc.Driver";
Class.forName(driver);
2. 获取数据库连接
注:mysql版本不同url的写法也略有差别
final String URL = "jdbc:mysql://localhost:3306/数据库名?useSSL=false";
final String USER = "root"; // 数据库用户名
final String PASSWORD = "123"; // 数据库密码
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
3. 创建命令对象
Statement stat = conn.createStatement();
3.1 三种Statement对象
- Statement:用于执行不带参数的简单SQL语句;
- PreparedStatement:Statement的子接口类型,PreparedStatement对象用于执行带或不带in参数的预编译SQL语句;可以避免SQL注入问题,提高SQL执行效率;
- CallableStatement:PreparedStatement的子接口类型,CallableStatement对象用于执行对数据库已存在的存储过程的调用;
3.2 SQL注入
select *from user where name='admin' and pwd=''or'1'='1';
4. 执行SQL语句,获取查询结果
String sql = "select * from website";
ResultSet resultSet = stat.executeQuery(sql);
4.1 执行SQL语句对象
- execute(sql); 可执行任意SQL语句(建议使用相关sql执行);返回值boolean:true表示返回的是一个结果集(查询sql语句),false: 表示不是一个结果集
- executeUpdate(sql); 执行增删改相关的SQL语句
- executeQuery(sql); 此方法执行查询的SQL语句
5. 关闭资源
conn.close(); // 仅关闭connection即可
三、JDBC API中的接口和类
- DriverManager: 这个类是JDBC的管理层,作用域用户和驱动程序之间。它跟踪可用的驱动程序,并在数据库和响应的驱动程序之间建立连接。
- Driver:此接口处理与数据库服务器的通信,通常由数据库厂商实现该接口。在进行Java Web开发时,程序员只需根据程序使用的驱动程序类型进行装载就行。
- Connection:此接口代表数据库连接。与数据库的所有通信都通过该对象连接。
- Statement:此接口代表SQL语句对象。可以向数据库发送任何SQL语句。
- ResultSet:它封装了查询返回的结果集对象。结果集是一个存储查询结果的对象,但是结果集不仅仅具有存储功能,同时后具有操纵数据的功能,可能完成对数据的更新等。
- SQLException:这个类处理发生在数据库操作过程中的任何错误。
四、批量操作
使用JDBC提供的一次执行多条sql语句。
如果需要多次执行某一条sql语句,每次获得执行sql命令对象只执行一条sql语句效率比较低,Statement接口提供了addBatch()方法和executeBatch()方法; 允许一次向sql命令的对象中批量添加sql语句,统一发送到数据库运行,提高效率;
// Statement批量操作
public class Insert1 {
public static void main(String[] args) {
String sql1 = "insert into user(name,gender,age,nationality) value('小蜜瓜','女',13,'CN')";
String sql2 = "insert into user(name,gender,age,nationality) value('小红薯','女',14,'CN')";
String sql3 = "insert into user(name,gender,age,nationality) value('小蜜桃','女',12,'CN')";
String sql4 = "insert into user(name,gender,age,nationality) value('小西瓜','男',11,'CN')";
try (Connection conn = DBUtil.getConnection()) {
Statement statement = conn.createStatement();
statement.addBatch(sql1);
statement.addBatch(sql2);
statement.addBatch(sql3);
statement.addBatch(sql4);
int[] res = statement.executeBatch();
System.out.println("受影响的行数:" + Arrays.toString(res));
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
}
}
// PreparedStatement批量操作
public class Insert2 {
public static void main(String[] args) {
String sql = "insert into user(name,gender,age,nationality) value(?, ?, ?, ?)";
try (Connection conn = DBUtil.getConnection()) {
PreparedStatement pst = conn.prepareStatement(sql);
for (int i = 0; i < 100; i++) {
pst.setString(1, "小蜜瓜" + i);
pst.setString(2, "女");
pst.setInt(3, i);
pst.setString(4, "CN");
pst.addBatch();
// 每20条执行一次,防止内存溢出
if (i % 20 == 0) {
pst.executeBatch();
}
}
pst.executeBatch();
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
}
}
五、数据库连接池
1. 什么是数据库连接池
数据库连接池是一个包含多个数据连接对象的容器。
数据库连接池可以避免频繁创建销毁带来的系统开销。连接池可以预先创建多个Connection对象,当有需要会自动创建关闭,还能规定最大连接数量,防止内存消耗。
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
2. 通过连接池获取数据库连接
// 这里使用的是dbcp连接池
public class DBUtil {
private static BasicDataSource bds;
static {
// 创建属性对象,该对象用于读取属性配置文件
Properties p = new Properties();
// 得到文件的输入流(见6.2)
InputStream in = DBUtil1.class.getClassLoader()
.getResourceAsStream("db.properties");
// 把文件加载到属性对象中
try {
p.load(in);
} catch (IOException e) {
e.printStackTrace();
}
// 读取数据
String driver = p.getProperty("driver");
String url = p.getProperty("url");
String username = p.getProperty("username");
String password = p.getProperty("password");
// 创建数据连接池对象
bds = new BasicDataSource();
// 为连接池中的连接对象设置基本参数信息
bds.setDriverClassName(driver);
bds.setUrl(url);
bds.setUsername(username);
bds.setPassword(password);
// 连接池连接对象管理策略
bds.setInitialSize(3); // 初始连接数量
bds.setMaxActive(5); // 最大连接数
bds.setMaxIdle(3); // 最大空闲连接数
}
public static Connection getConnection() throws SQLException {
// 从连接池中获取连接
return bds.getConnection();
}
}
六、获取数据库连接的方式
1. 直接获取
public class DBUtil1 {
public static Connection getConnection() {
final String driver = "com.mysql.jdbc.Driver";
final String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false";
final String username = "root";
final String password = "123";
Connection connection = null;
try {
// 1. 加载驱动
Class.forName(driver);
// 2. 获取连接
connection = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
}
2. properties文件获取
db.properties 文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC
username=root
password=123
public class DBUtil {
public static Connection getConnection() {
Connection connection = null;
try {
// 创建属性对象,该对象用于读取属性配置文件
Properties p = new Properties();
// 得到文件的输入流
InputStream in = DBUtil1.class.getClassLoader()
.getResourceAsStream("db.properties");
// 把文件加载到属性对象中
p.load(in);
// 读取数据
String driver = p.getProperty("driver");
String url = p.getProperty("url");
String username = p.getProperty("username");
String password = p.getProperty("password");
// 1. 加载驱动
Class.forName(driver);
// 2. 获取连接
connection = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
}
3. 连接池获取
见5.2
七、练习
1. 创建UserBean
UserBean就是一个javaBean,javaBean实际上就是一个Java类,用于封装从数据库中查询出的数据。
public class UserBean {
private int id;
private String name;
private String gender;
private int age;
private String nationality; // 国籍
// 无参、全参构造略...
// getter,setter,toString方法略...
}
2. 创建操作类UserDao
UserDao中封装了操作相关数据表的方法。如:添加数据、删除、修改、查询数据等
public class UserDao {
// 添加
public void addUser(UserBean user) {
String sql = "insert into user(name, gender, age, nationality) value(?,?,?,?)";
try(Connection conn = DBUtil.getConnection()) {
// 预编译SQL(可以提高sql执行效率,避免SQL注入)
PreparedStatement ptmt = ptmt = conn.prepareStatement(sql);
// 传参. 1对应第一个? name;2对应第二个? url ...
ptmt.setString(1, user.getName());
ptmt.setString(2, user.getGender());
ptmt.setInt(3, user.getAge());
ptmt.setString(4, user.getNationality());
// 获取返回结果,这里返回受影响的行数
int rows = ptmt.executeUpdate();
System.out.println("添加数据受影响的行数:" + rows);
} catch (SQLException e) {
e.printStackTrace();
}
}
// 更新
public void updateUser(UserBean user) {
String sql = "update user set gender=?, age=?, nationality=? where name=?";
try(Connection conn = DBUtil.getConnection()) {
PreparedStatement ptmt = connection.prepareStatement(sql);
ptmt.setString(1, user.getGender());
ptmt.setInt(2, user.getAge());
ptmt.setString(3, user.getNationality());
ptmt.setString(4, user.getName());
int rows = ptmt.executeUpdate();
System.out.println("更新数据受影响的行数:" + rows);
} catch (SQLException e) {
e.printStackTrace();
}
}
// 删除
public void delWebsite(int id) {
try(Connection conn = DBUtil.getConnection()) {
PreparedStatement ptmt = conn.prepareStatement("delete from user where id = ?");
ptmt.setInt(1, id);
int rows = ptmt.executeUpdate();
System.out.println("删除数据受影响的行数:" + rows);
} catch (SQLException e) {
e.printStackTrace();
}
}
// 查询所有
public void findAllUser() {
final Connection connection = DBUtil.getConnection();
try(Connection conn = DBUtil.getConnection()) {
PreparedStatement ptmt = conn.prepareStatement("select * from user");
ResultSet resSet = ptmt.executeQuery();
while (resSet.next()) {
int id = rSet.getInt("id");
String name = rSet.getString("name");
String gender = rSet.getString("gender");
int age = rSet.getInt("age");
String nationality = rSet.getString("nationality");
System.out.println(id + "--" + name + "--" + gender + "--" + age + "--" + nationality);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
// 根据id查询user
public void findUserById(int id) {
String sql = "select * from user where id = ?";
try (Connection connection = DBUtil.getConnection()) {
PreparedStatement pst = connection.prepareStatement(sql);
pst.setInt(1, id);
ResultSet resSet = pst.executeQuery();
resSet.next();
int id = rSet.getInt("id");
String name = rSet.getString("name");
String gender = rSet.getString("gender");
int age = rSet.getInt("age");
String nationality = rSet.getString("nationality");
System.out.println(id + "--" + name + "--" + gender + "--" + age + "--" + nationality);
} catch (SQLException e) {
e.printStackTrace();
}
}
}