JDBC笔记
JDBC
基本概念
(JDBC)Java DataBase Connectivity
Java 数据库连接, Java语言操作数据库
JDBC本质
官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。
各个数据库厂商去实现这套接口,提供数据库驱动jar包。
我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
使用步骤
- 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
- 复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下
- 右键–>Add As Library(添加到依赖库)
- 注册驱动
- 获取数据库连接对象 Connection
- 定义sql
- 获取执行sql语句的对象 Statement
- 执行sql,接受返回结果
- 处理结果
- 释放资源
测试代码
import java.sql.*;
public class JdbcDemo1 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 获取数据库连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcstu", "root", "123456");
// 编写sql
String sql = "select * from demo1";
// 获取sql执行对象
Statement state = connection.createStatement();
// 执行sql获取返回结果
ResultSet rs = state.executeQuery(sql);
// 遍历获取结果
int id;
String name;
int age;
while(rs.next()) {
id = rs.getInt(1);
name = rs.getString(2);
age = rs.getInt(3);
System.out.println(id + " " + name + " " + age);
}
// 释放资源
rs.close();
state.close();
connection.close();
}
}
相关对象
DriverManager: 驱动管理对象
1. 注册驱动:告诉程序该使用哪一个数据库驱动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:密码
Connection:数据库连接对象
1. 功能:
1. 获取执行sql 的对象
Statement createStatement()
PreparedStatement prepareStatement(String sql)
2. 管理事务:
开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
提交事务:commit()
回滚事务:rollback()
Statement:执行sql的对象
1. 执行sql
1. boolean execute(String sql) :可以执行任意的sql 了解
2. int executeUpdate(String sql) :执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句
返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。
3. ResultSet executeQuery(String sql) :执行DQL(select)语句
ResultSet:结果集对象,封装查询结果
boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true
getXxx(参数):获取数据
Xxx:代表数据类型 如: int getInt() , String getString()
参数:
1. int:代表列的编号,从1开始 如: getString(1)
2. String:代表列名称。 如: getDouble("balance")
使用步骤:
1. 游标向下移动一行
2. 判断是否有数据
3. 获取数据
PreparedStatement:执行sql的对象
1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
1. 输入用户随便,输入密码:a' or 'a' = 'a
2. sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'
2. 解决sql注入问题:使用PreparedStatement对象来解决
3. 预编译的SQL:参数使用?作为占位符
4. 步骤:
1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
2. 注册驱动
3. 获取数据库连接对象 Connection
4. 定义sql
* 注意:sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
5. 获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)
6. 给?赋值:
* 方法: setXxx(参数1,参数2)
* 参数1:?的位置编号 从1 开始
* 参数2:?的值
7. 执行sql,接受返回结果,不需要传递sql语句
8. 处理结果
9. 释放资源
5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
1. 可以防止SQL注入
2. 效率更高
测试代码
import java.sql.*;
public class JdbcDemo2 {
public static void main(String[] args) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcstu", "root", "123456");
String sql = "select * from demo1 where age > ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 18);
ResultSet res = ps.executeQuery();
while(res.next()) {
System.out.println(res.getInt(1) +
" " + res.getString(2) +
" " + res.getInt(3));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
封装JDBC工具类:JdbCUtils
目的:简化书写
分析:
1. 注册驱动也抽取
2. 抽取一个方法获取连接对象
需求:不想传递参数(麻烦),还得保证工具类的通用性。
解决:配置文件
jdbc.properties
url=
user=
password=
3. 抽取一个方法释放资源
JdbCUtils代码
import java.net.URL;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver;
private static String url;
private static String username;
private static String password;
// 静态域初始化
static {
try {
Properties props = new Properties();
String fileName = "jdbc.properties";
URL resource = JdbcUtils.class.getClassLoader().getResource(fileName);
props.load(resource.openStream());
driver = props.getProperty("driver");
url = props.getProperty("url");
username = props.getProperty("username");
password = props.getProperty("password");
// 加载驱动
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接
* */
public static Connection getConnection() throws SQLException {
System.out.println("获取连接");
return DriverManager.getConnection(url, username, password);
}
/**
* 释放资源
* */
public static void close(Statement statement, Connection connection, ResultSet resultSet) {
if(resultSet !=null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement !=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection !=null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
System.out.println("释放资源");
}
public static void close(Statement statement, Connection connection) {
if(statement !=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection !=null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
System.out.println("释放资源");
}
}
测试代码
import org.example.utils.JdbcUtils;
import java.sql.*;
public class JdbcDemo3 {
public static void main(String[] args) {
try {
// 获取连接
Connection conn = JdbcUtils.getConnection();
PreparedStatement preparedStatement = conn.prepareStatement("select * from demo1 where name = ?");
preparedStatement.setString(1, "张三");
ResultSet resultSet = preparedStatement.executeQuery();
int id;
String name;
int age;
// 获取数据
while(resultSet.next()) {
id = resultSet.getInt(1);
name = resultSet.getString(2);
age = resultSet.getInt(3);
System.out.println(id + " " + name + " " + age);
}
// 释放资源
JdbcUtils.close(preparedStatement, conn, resultSet);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
运行结果
获取连接
1 张三 15
释放资源
JDBC事务控制
1. 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
2. 操作:
1. 开启事务
2. 提交事务
3. 回滚事务
3. 使用Connection对象来管理事务
开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
在执行sql之前开启事务
提交事务:commit()
当所有sql都执行完提交事务
回滚事务:rollback()
在catch中回滚事务
数据库连接池
概念
概念:一个容器(集合),存放数据库连接的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
好处:
节约资源
用户访问高效
实现:
标准接口:DataSource javax.sql包下的
方法:
获取连接:getConnection()
归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接
一般我们不去实现它,有数据库厂商来实现
C3P0:数据库连接池技术
Druid:数据库连接池实现技术,由阿里巴巴提供的
c3p0
使用步骤:
1. 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar
不要忘记导入数据库驱动jar包
/或者直接使用maven(添加坐标到pom.xml)
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
2. 定义配置文件:
名称: c3p0.properties 或者 c3p0-config.xml
路径:直接将文件放在src目录下即可。(idea项目将配置文件放到resources目录下,否则运行时会没有配置文件报错)
配置文件内容(c3p0.properties为例,具体参看官方文档配置):
# turn on statement pooling
c3p0.maxStatements=10
# close pooled Connections that go unused for
# more than half an hour
c3p0.maxIdleTime=1800
# driver class
c3p0.driverClass=com.mysql.cj.jdbc.Driver
#jdbcUrl
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/jdbcstu
#user
c3p0.user=root
#password
c3p0.password=123456
3. 创建核心对象 数据库连接池对象 ComboPooledDataSource
4. 获取连接: getConnection
代码:
//1.创建数据库连接池对象
DataSource ds = new ComboPooledDataSource();
//2. 获取连接对象
Connection conn = ds.getConnection();
测试代码
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class C3p0Demo1 {
public static void main(String[] args) throws SQLException {
DataSource dataSource = new ComboPooledDataSource();
Connection connection = dataSource.getConnection();
String sql = "select * from demo1";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while(rs.next()) {
int id = rs.getInt(1);
String name = rs.getString(2);
int age = rs.getInt(3);
String password = rs.getString(4);
System.out.println(id+" "+name+" "+age+" "+password);
}
rs.close();
stmt.close();
}
}
运行结果
1 张三 15 123456
2 李思 16 111111
3 王五 19 100861
Druid
Druid:数据库连接池实现技术,由阿里巴巴提供的
步骤:
1. 导入jar包 druid-1.0.9.jar
/或者直接使用maven(添加坐标到pom.xml)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.11</version>
</dependency>
2. 定义配置文件:
* 是properties形式的
* 可以叫任意名称,可以放在任意目录下(idea项目将配置文件放到resources目录下,否则运行时会没有配置文件报错)
* druid.properties 配置文件内容示例:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///jdbcstu
username=root
password=123456
initialSize=5
maxActive=10
maxWait=3000
3. 加载配置文件。Properties
4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
5. 获取连接:getConnection
代码:
//加载配置文件
Properties pro = new Properties();
InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//获取连接
Connection conn = ds.getConnection();
JdbcUtils(添加如下方法,其他内容同上JdbcUtils)
/**
* @return DataSource(Druid)
* @throws Exception
*/
public static DataSource getDataSource() throws Exception {
// 配置
Properties properties = new Properties();
InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(is);
// 获取DataSoource
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
return dataSource;
}
测试代码
import domain.User;
import org.example.utils.JdbcUtils;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.List;
public class DruidDemo1 {
public static void main(String[] args) throws Exception {
//获取连接池
DataSource dataSource = JdbcUtils.getDataSource();
Connection connection = dataSource.getConnection();
List<User> users = new LinkedList<User>();
String sql = "select * from demo1";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);
User user = new User();
while(rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
String password = rs.getString("password");
user.setId(id);
user.setName(name);
user.setAge(age);
user.setPassword(password);
users.add(user);
}
System.out.println(users);
rs.close();
stmt.close();
connection.close();
}
}
运行结果
[User{id=3, name='王五', age=19, password='100861'}, User{id=3, name='王五', age=19, password='100861'}, User{id=3, name='王五', age=19, password='100861'}]
domain下的User类
public class User {
private int id;
private String name;
private int age;
private String password;
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", password='" + password + '\'' +
'}';
}
}
Spring JDBC
概念
Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发
使用步骤
1.导入jar包/maven项目(修改pom.xml)
依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.21</version>
</dependency>
3.创建JdbcTemplate对象。依赖于数据源DataSource
JdbcTemplate template = new JdbcTemplate(ds);
4.调用JdbcTemplate的方法来完成CRUD的操作
update():执行DML语句。增、删、改语句
queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
注意:这个方法查询的结果集长度只能是1
queryForList():查询结果将结果集封装为list集合
注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
query():查询结果,将结果封装为JavaBean对象
query的参数:RowMapper
一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
new BeanPropertyRowMapper<类型>(类型.class)
queryForObject:查询结果,将结果封装为对象
一般用于聚合函数的查询
测试代码
import domain.User;
import org.example.utils.JdbcUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.util.List;
public class JdbcTemplateDemo1
{
private static DataSource dataSource;
private static JdbcTemplate jdbcTemplate;
static {
try {
dataSource = JdbcUtils.getDataSource();
jdbcTemplate = new JdbcTemplate(dataSource);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
// 查询
JdbcTemplateDemo1.queryUser();
// 添加一个用户
User user = new User();
user.setId(4);
user.setName("老王");
user.setAge(45);
user.setPassword("1001011");
JdbcTemplateDemo1.addUser(user);
// 查询
JdbcTemplateDemo1.queryUser();
// 修改
JdbcTemplateDemo1.modifyUser(4, "12121212");
// 查询
JdbcTemplateDemo1.queryUser();
//删除
JdbcTemplateDemo1.delUser(4);
// 查询
JdbcTemplateDemo1.queryUser();
}
// 增加
public static void addUser(User user) {
String sql = "insert into demo1(id, name, age, password) values(?,?,?,?)";
int res = jdbcTemplate.update(sql, user.getId(), user.getName(), user.getAge(), user.getPassword());
if(res > 0) {
System.out.println("添加" + user + "成功");
}
}
// 删除
public static void delUser(int userid) {
String sql = "delete from demo1 where id = ?";
int res = jdbcTemplate.update(sql, userid);
if (res > 0) {
System.out.println("删除 id:" + userid + "用户成功");
}
}
// 修改密码
public static void modifyUser(int userid, String password) {
String sql = "update demo1 set password = ? where id = ? ";
int res = jdbcTemplate.update(sql, password, userid);
if(res > 0) {
System.out.println("id:" + userid + " 修改密码成功");
}
}
// 查询
public static void queryUser() {
String sql = "select * from demo1";
List<User> users = jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class));
System.out.println("当前表数据:");
for(User user: users) {
System.out.println(user);
}
}
}
运行结果
当前表数据:
User{id=1, name='张三', age=15, password='123456'}
User{id=2, name='李思', age=16, password='111111'}
User{id=3, name='王五', age=19, password='100861'}
添加User{id=4, name='老王', age=45, password='1001011'}成功
当前表数据:
User{id=1, name='张三', age=15, password='123456'}
User{id=2, name='李思', age=16, password='111111'}
User{id=3, name='王五', age=19, password='100861'}
User{id=4, name='老王', age=45, password='1001011'}
id:4 修改密码成功
当前表数据:
User{id=1, name='张三', age=15, password='123456'}
User{id=2, name='李思', age=16, password='111111'}
User{id=3, name='王五', age=19, password='100861'}
User{id=4, name='老王', age=45, password='12121212'}
删除 id:4用户成功
当前表数据:
User{id=1, name='张三', age=15, password='123456'}
User{id=2, name='李思', age=16, password='111111'}
User{id=3, name='王五', age=19, password='100861'}