一、JDBC基本使用
1.JDBC概述
概念:Java DataBase Connectivity Java 数据库连接, Java语言操作数据库
JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。我们只需要使用不同的jar包中的对象进行操作即可
2. JDBC入门
jdbc的快速入门可以让我们快速掌握jdbc的步骤:
1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
1.复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下
2.右键–>Add As Library
2. 注册驱动
3. 获取数据库连接对象 Connection
4. 定义sql
5. 获取执行sql语句的对象 Statement
6. 执行sql,接受返回结果
7. 处理结果
8. 释放资源
代码实现:
//1. 导入驱动jar包
//2.注册驱动 (连接不同的数据库,注册不同的驱动)
Class.forName("com.mysql.jdbc.Driver");
//3.获取数据库连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "root");
//4.定义sql语句
String sql = "update account set balance = 500 where id = 1";
//5.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//6.执行sql
int count = stmt.executeUpdate(sql);
//7.处理结果
System.out.println(count);
//8.释放资源
stmt.close();
conn.close();
3. JDBC常用API
DriverManager:驱动管理对象
Connection:数据库连接对象
Statement:执行sql的对象
ResultSet:结果集对象,封装查询结果
PreparedStatement:执行sql的对象(比Statement功能更多)
- 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. 获取执行sql 的对象
* Statement createStatement()
* PreparedStatement prepareStatement(String sql)
注意:二者的区别在于后者可以防止漏洞注入,后面会有讲解
2. 管理事务:
* 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
* 提交事务:commit()
* 回滚事务:rollback()
- Statement:执行sql的对象
Statement是用于执行静态sql的执行sql对象,还有一个就是prepareStatement用于执行预编译sql对象,
静态sql就是sql语句不变的,预编译就是sql是动态的,带有?符号的。后续讲解prepareStatement防止漏洞注入在讲解
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:结果集对象,封装查询结果
该对象是在执行executeQuery(String sql)方法执行查询sql语句的时候会返回结果集对象
功能
* boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回 false,如果不是则返回true
* getXxx(参数):获取数据
* Xxx:代表数据类型 如: int getInt() , String getString() ,Object getObject()
* 参数:
1. int:代表列的编号,从1开始 如: getString(1)
2. String:代表列名称。 如: getDouble("balance")
* 注意:
* 使用步骤:
1. 游标向下移动一行
2. 判断是否有数据
3. 获取数据
//循环判断游标是否是最后一行末尾。
while(rs.next()){
//获取数据
//6.2 获取数据
int id = rs.getInt(1);
String name = rs.getString("name");
double balance = rs.getDouble(3);
System.out.println(id + "---" + name + "---" + balance);
}
注意:
1.当rs.next()方法判断下一行有数据时,使用rs对象调用getXxx(?)依次把该行数据的所有列信息获取出来
2.查询的结果集如果是多行时,使用循环迭代,如果查询的结果是单行时,其实可以直接使用if即可
3.使用完毕以后要关闭结果集 ResultSet,再关闭 Statement,再关闭 Connection
JDBC的资源释放
- 概述
数据库的连接数是有上限的,使用者需要及时地将连接关闭释放。
- 代码实现
// 官方推荐
if (null != connection) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
if (null != resultSet) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
resultSet = null;
}
4. JDBC的增删改查案例
- 代码实现
public class Demo03 {
public static void main(String[] args) {
// add();
// delete();
// update();
// selectOne();
selectAll();
}
private static void selectAll() {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
//1,加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
//2,获取连接
String url = "jdbc:mysql://localhost:3306/day27";
String user = "root";
String password = "root";
connection = DriverManager.getConnection(url, user, password);
//3,获取执行sql对象
statement = connection.createStatement();
//4,编写sql,执行sql
String sql = "select * from tb_user ";
resultSet = statement.executeQuery(sql);
List<User> userList = new ArrayList<>();
while (resultSet.next()) {
User existUser = new User(
resultSet.getInt(1),
resultSet.getString(2),
resultSet.getDouble(3)
);
userList.add(existUser);
}
System.out.println(userList);
} catch (Exception e) {
e.printStackTrace();
} finally {
//5,释放资源
if (null != connection) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
if (null != resultSet) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
resultSet = null;
}
}
}
private static void selectOne() {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
//1,加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
//2,获取连接
String url = "jdbc:mysql://localhost:3306/day27";
String user = "root";
String password = "root";
connection = DriverManager.getConnection(url, user, password);
//3,获取执行sql对象
statement = connection.createStatement();
//4,编写sql,执行sql
String sql = "select * from tb_user where id = 1";
resultSet = statement.executeQuery(sql);
User existUser = null;
if (resultSet.next()) {
existUser = new User(
resultSet.getInt(1),
resultSet.getString(2),
resultSet.getDouble(3)
);
}
System.out.println(existUser);
} catch (Exception e) {
e.printStackTrace();
} finally {
//5,释放资源
if (null != connection) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
if (null != resultSet) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
resultSet = null;
}
}
}
private static void update() {
Connection connection = null;
Statement statement = null;
try {
//1,加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2,获取连接
String url = "jdbc:mysql://localhost:3306/day27";
String user = "root";
String password = "root";
connection = DriverManager.getConnection(url, user, password);
//3,获取执行sql对象
statement = connection.createStatement();
//4,编写sql,执行sql
String sql = "update tb_user set money = money + 5000 where name = '张三'";
statement.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
} finally {
//5,释放资源
if (null != connection) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
}
}
private static void delete() {
Connection connection = null;
Statement statement = null;
try {
//1,加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2,获取连接
String url = "jdbc:mysql://localhost:3306/day27";
String user = "root";
String password = "root";
connection = DriverManager.getConnection(url, user, password);
//3,获取执行sql对象
statement = connection.createStatement();
//4,编写sql,执行sql
String sql = "delete from tb_user where id = 1";
statement.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
} finally {
//5,释放资源
if (null != connection) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
}
}
private static void add() {
Connection connection = null;
Statement statement = null;
try {
//1,加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2,获取连接
String url = "jdbc:mysql://localhost:3306/day27";
String user = "root";
String password = "root";
connection = DriverManager.getConnection(url, user, password);
//3,获取执行sql对象
statement = connection.createStatement();
//4,编写sql,执行sql
String sql = "insert into tb_user values(null,'张三',10000)";
statement.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
} finally {
//5,释放资源
if (null != connection) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
}
}
}
5. 抽取JDBC工具类 : JDBCUtils
我们发现之前写的代码会有一些问题,每一次在进行操作数据的时候都需要重复的注册驱动,获取连接。我们可以直接抽取一个工具类帮助我们来完成这些操作,简化代码!
抽取的工具类方法:
public class JDBCUtils {
private static final String DRIVER_CLASS ;
private static final String URL ;
private static final String USER ;
private static final String PASSWORD ;
static {
Properties properties = new Properties();
try {
//1. 创建Properties集合类。
Properties pro = new Properties();
//获取src路径下的文件的方式--->ClassLoader 类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
//获取配置文件所对应的输入流。参数是文件名,获取文件的相对资源路径
InputStream in = classLoader.getResourceAsStream("jdbc.properties");
//将输入流和对象绑定
pro.load(in);
} catch (IOException e) {
e.printStackTrace();
}
//3. 获取数据,赋值
DRIVER_CLASS = properties.getProperty("driverClass");
URL = properties.getProperty("url");
USER = properties.getProperty("user");
PASSWORD = properties.getProperty("password");
}
private static void loadDriver() throws ClassNotFoundException {
Class.forName(DRIVER_CLASS);
}
public static Connection getConnection() throws SQLException, ClassNotFoundException {
loadDriver();
return DriverManager.getConnection(URL, USER, PASSWORD);
}
public static void release(Connection connection, Statement statement, ResultSet resultSet) {
if (null != connection) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
if (null != resultSet) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
resultSet = null;
}
}
public static void release(Connection connection, Statement statement){
release(connection,statement,null);
}
}
- 配置文件:jdbc.properties
url=jdbc:mysql:///db3
user=root
password=root
driverClass=com.mysql.jdbc.Driver
6. SQL注入漏洞
SQL注入的漏洞在早期互联网中是普遍存在.
* 在已知用户名的情况下.对这个用户名的用户进行攻击!!!
* 1.攻击方式一:
* 在用户名地方输入:aaa' or '1=1
* 密码随意.
* 2.攻击方式二:
* 在用户名地方输入:aaa' --
* 密码随意.
* 产生原因:因为在用户名地方输入SQL的关键字.(SQL注入)
*登录案例中SQL语句:
* select * from user where username = '' and password = '';
* 产生原因一:
* select * from user where username = 'aaa' or '1=1' and password = 'xxxx';
* 产生原因二:
* select * from user where username = 'aaa' -- ' and password = 'xxxx';
解决:
SQL注入漏洞真正的解决方案:PreparedStatement.对SQL进行预编译.参数的地方都可以使用 ? 作为占位符.
select * from user where username = ? and password = ?;
a.再次输入 aaa' or '1=1 拿到参数之后. or 一些特殊的字符 不当成SQL的关键字。只是当成普通的字符串进行解析.
b.提前进行编译.编译后的SQL的格式就已经固定了.
使用PreparedStatement改写了登录案例解决了SQL注入的漏洞!!!
代码:
//2.定义sql
String sql = "select * from user where username = ? and password = ?";
//3.获取执行sql的对象
pstmt = conn.prepareStatement(sql);
//给?赋值
pstmt.setString(1,username);
pstmt.setString(2,password);
//4.执行查询,不需要传递sql
rs = pstmt.executeQuery();
二、数据库连接池
2.1 概念
1.其实就是一个容器(集合),存放数据库连接(connection)的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
2.好处:
- 节约资源
- 用户访问高效
注意:在之前操作数据库的时候每次在获取连接对象操作完毕后都进行了关闭资源,当再次操作数据库的时候又需要重新获取连接对象,然后用完再关闭资源,等到再次使用连接对象的时候又要重新获取。其实获取连接对象是一件非常耗时的事情,而且用完就关闭就好比:饭店有人吃饭就招服务员,没有人吃饭了就辞退服务员,等再来人再重新招服务员,这就是有我们之前写代码的逻辑,显然这样的逻辑是不可取的!
而连接池其实就是创建几个连接对象在一个池子中,有人使用就从这个池子里获取,用完就自动归还到池子中,而不是关闭,方便下一次的操作获取
连接池一般我们不去实现,有数据库厂商来实现,我们只需要进行操作使用即可
- C3P0:数据库连接池技术
- Druid:数据库连接池实现技术,由阿里巴巴提供的
- dbcp : 数据库连接池技术,(不常用)。
2.2 JDBCUtils工具类结合c3p0
- 代码实现
// 与下面的配置文件搭配使用(二选一)
public class JDBCUtils2 {
private static final ComboPooledDataSource dataSource = new ComboPooledDataSource();
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void release(Connection connection, Statement statement , ResultSet resultSet){
if (null != connection) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
if (null != resultSet) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
resultSet = null;
}
}
public static void release(Connection connection, Statement statement ){
release(connection, statement,null);
}
}
- c3p0-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///day27</property>
<property name="user">root</property>
<property name="password">root</property>
<!--增加连接数-->
<property name="acquireIncrement">10</property>
<!--初始连接数-->
<property name="initialPoolSize">10</property>
<!--最大空闲时间-->
<property name="maxIdleTime">30</property>
<!--最大连接数-->
<property name="maxPoolSize">100</property>
<!--最小连接数-->
<property name="minPoolSize">5</property>
</default-config>
</c3p0-config>
- c3p0.properties
# 设置驱动名称
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql:///day27
c3p0.user=root
c3p0.password=root
c3p0.acquireIncrement=10
c3p0.maxIdleTime=1800
c3p0.initialPoolSize=10
c3p0.maxPoolSize=100
c3p0.minPoolSize=10
2.4 开源连接池之Druid
- 使用方式
- java代码
- properties配置文件
- 代码实现
- java代码
public class Demo04 {
public static void main(String[] args) {
//1,创建druid连接池对象
DruidDataSource dataSource = new DruidDataSource();
//2,设置参数
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///day27");
dataSource.setUsername("root");
dataSource.setPassword("root");
PreparedStatement statement = null;
ResultSet resultSet = null;
Connection connection = null;
//3,获取连接
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("select * from tb_user");
resultSet = statement.executeQuery();
List<User> userList = new ArrayList<>();
while (resultSet.next()) {
User user = new User();
user.setId(resultSet.getInt("id"));
user.setName(resultSet.getString("name"));
user.setPassword(resultSet.getString("password"));
user.setMoney(resultSet.getDouble("money"));
userList.add(user);
}
System.out.println(userList);
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if (null != connection) {
try {
connection.close();//归还连接
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
if (null != resultSet) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
resultSet = null;
}
}
}
}
- druid.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///day27
username=root
password=root
- 配置文件方式
public class Demo05 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
Properties properteis = new Properties();
properteis.load(Demo05.class.getClassLoader().getResourceAsStream("druid.properties"));
DataSource dataSource = DruidDataSourceFactory.createDataSource(properteis);
connection = dataSource.getConnection();
statement = connection.prepareStatement("select * from tb_user");
resultSet = statement.executeQuery();
List<User> userList = new ArrayList<>();
while (resultSet.next()) {
User user = new User();
user.setId(resultSet.getInt("id"));
user.setName(resultSet.getString("name"));
user.setPassword(resultSet.getString("password"));
user.setMoney(resultSet.getDouble("money"));
userList.add(user);
}
System.out.println(userList);
} catch (Exception e) {
e.printStackTrace();
}finally {
if (null != connection) {
try {
connection.close();//归还连接
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
if (null != resultSet) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
resultSet = null;
}
}
}
}
2.5 事务管理案列
-
代码实现
-
JDBCUtils2.java
public class JDBCUtils2 {
private static final ComboPooledDataSource dataSource = new ComboPooledDataSource();
//获取ThreadLocal容器对象
private static final ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
public static Connection getConnection() throws SQLException {
Connection connection = threadLocal.get();
if (null == connection) {
//第一次获取连接,直接创建 , 将该连接保存到容器中
connection = dataSource.getConnection();
threadLocal.set(connection);
}
return connection;
}
/**
* 开启事务
*/
public static void startTransaction() throws SQLException {
getConnection().setAutoCommit(false);
}
public static void rollback() throws SQLException {
getConnection().rollback();
}
public static void commit() throws SQLException {
getConnection().commit();
}
public static void closeConnection() throws SQLException {
Connection connection = getConnection();
if (null != connection) {
connection.close();//归还
threadLocal.remove();//将该连接从ThreadLocal中移除!
}
}
public static void release(Connection connection, Statement statement , ResultSet resultSet){
if (null != connection) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
if (null != resultSet) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
resultSet = null;
}
}
public static void release(Connection connection, Statement statement ){
release(connection, statement,null);
}
}
- UserDao.java
public class UserDao {
/**
* 出账
* @param outName
* @param money
*/
public void outMoney(String outName , double money){
Connection connection = null;
PreparedStatement statement = null;
try {
connection = JDBCUtils2.getConnection();
statement = connection.prepareStatement("update tb_user set money = money - ? where name = ?");
statement.setDouble(1, money);
statement.setString(2, outName);
statement.executeUpdate();
} catch (Exception throwables) {
throwables.printStackTrace();
} finally {
// JDBCUtils2.release(connection,statement);
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
}
}
/**
* 入账
* @param inName
* @param money
*/
public void inMoney(String inName , double money){
Connection connection = null;
PreparedStatement statement = null;
try {
connection = JDBCUtils2.getConnection();
statement = connection.prepareStatement("update tb_user set money = money + ? where name = ?");
statement.setDouble(1, money);
statement.setString(2, inName);
statement.executeUpdate();
} catch (Exception throwables) {
throwables.printStackTrace();
} finally {
// JDBCUtils2.release(connection,statement);
if (null != statement) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
statement = null;
}
}
}
}
- 测试
public class Demo08 {
public static void main(String[] args) {
transfer("张三","王麻子",100);
}
/**
* 转账
*/
public static void transfer(String outName , String inName, double money){
Connection connection = null;
try {
//开启事务
connection = JDBCUtils2.getConnection();
connection.setAutoCommit(false);
UserDao userDao = new UserDao();
//出账
userDao.outMoney(outName,money);
// int num = 1 / 0;
//入账
userDao.inMoney(inName,money);
} catch (Exception e) {
e.printStackTrace();
//回滚事务
try {
connection.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} finally {
//提交事务
try {
connection.commit();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
if (null != connection) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
connection = null;
}
}
}
}
2.6 DbUtils工具类
- 概述
Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。
- 代码实现
public class Demo10 {
public static void main(String[] args) throws SQLException {
// add();
// delete();
// update();
// selectOne();
selectAll();
}
private static void selectAll() throws SQLException {
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
List<User> userList = queryRunner.query("select * from tb_user", new ResultSetHandler<List<User>>() {
@Override
public List<User> handle(ResultSet resultSet) throws SQLException {
List<User> userList = new ArrayList<>();
while (resultSet.next()) {
User user = new User();
user.setId(resultSet.getInt("id"));
user.setName(resultSet.getString("name"));
user.setPassword(resultSet.getString("password"));
user.setMoney(resultSet.getDouble("money"));
userList.add(user);
}
return userList;
}
});
System.out.println(userList);
System.out.println("-----------------");
List<User> userList1 = queryRunner.query("select * from tb_user", new BeanListHandler<User>(User.class));
System.out.println(userList1);
}
private static void selectOne() throws SQLException {
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
User existUser = queryRunner.query("select * from tb_user where id = ?", new ResultSetHandler<User>() {
@Override
public User handle(ResultSet resultSet) throws SQLException {
User user = null;
if (resultSet.next()) {
user = new User();
user.setId(resultSet.getInt("id"));
user.setName(resultSet.getString("name"));
user.setPassword(resultSet.getString("password"));
user.setMoney(resultSet.getDouble("money"));
}
return user;
}
}, 2);
System.out.println(existUser);
System.out.println("-----------------");
User existUser2 = queryRunner.query("select * from tb_user where id = ?", new BeanHandler<User>(User.class), 9);
System.out.println(existUser2);
}
private static void update() throws SQLException {
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
queryRunner.update("update tb_user set money = ? where name = ?",50000,"张三");
}
private static void delete() throws SQLException {
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
queryRunner.update("delete from tb_user where id = ?" ,10);
}
private static void add() throws SQLException {
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
//sql
//Object... : 设置参数
queryRunner.update("insert into tb_user values(null,?,?,?)","王八",10000,"root");
}
}
三、SpringJdbc
前言:之前在使用了连接池后,我们发现我们连接对象复用性更高了,整个程序的性能也更高了。但是!我们具体在做jdbc操作的时候,其实还是比较麻烦的,我们要定义sql、执行sql、设置参数、处理结果。特别是在处理结果的时候,我们如果做的是查询操作的话,会非常的麻烦,需要获取一个个的数据再封装成对象!
这个过程非常麻烦,其实都是体力活。我们只需要定义好sql,执行完sql就好了,这些体力活其实我们是不希望自己来进行操作处理的。所以今天我们来学习一个jdbc的简单工具类,简化程序的开发步骤。
3.1 springjdbc的概念
springjdbc是spring框架提供的jdbc简单封装。它提供了一个JDBCTemplate对象简化JDBC的开发
既然是spring框架提供的,那么也需要导入jar。
下载地址::https://mvnrepository.com/
步骤:
1. 导入jar包
2. 创建JdbcTemplate对象。依赖于数据源DataSource(这个数据源可以直接从上面自定义的工具类中获取)
* JdbcTemplate template = new JdbcTemplate(ds);
3. 调用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:查询结果,将结果封装为对象
3.2 JdbcTemplate快速入门
import org.springframework.jdbc.core.JdbcTemplate;
/**
* JdbcTemplate入门
*/
public class JdbcTemplateDemo1 {
public static void main(String[] args) {
//1.导入jar包
//2.创建JDBCTemplate对象,参数给上数据源
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//3.调用方法,只需要关注传递sql语句和?参数即可,而且update方法可以通用增删改
String sql = "update account set balance = 5000 where id = ?";
int count = template.update(sql, 3);
//操作完毕后会自动把连接对象归还和释放
System.out.println(count);
}
}
3.3 基本案例练习
- 需求:emp员工表
- 修改1号数据的 salary 为 10000
- 添加一条记录
- 删除刚才添加的记录
- 查询id为1的记录,将其封装为Map集合
- 查询所有记录,将其封装为List
- 查询所有记录,将其封装为Emp对象的List集合
- 查询总记录数
代码:
import cn.Emp;
import cn.itcast.utils.JDBCUtils;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
public class JdbcTemplateDemo2 {
//Junit单元测试,可以让方法独立执行.直接写注解@Test进行导入
//获取JDBCTemplate对象
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 1. 修改1号数据的 salary 为 10000
*/
@Test
public void test1(){
//2. 定义sql
String sql = "update emp set salary = 10000 where id = 1001";
//3. 执行sql
int count = template.update(sql);
System.out.println(count);
}
/**
* 2. 添加一条记录
*/
@Test
public void test2(){
String sql = "insert into emp(id,ename,dept_id) values(?,?,?)";
int count = template.update(sql, 1015, "郭靖", 10);
System.out.println(count);
}
/**
* 3.删除刚才添加的记录
*/
@Test
public void test3(){
String sql = "delete from emp where id = ?";
int count = template.update(sql, 1015);
System.out.println(count);
}
/**
* 4.查询id为1001的记录,将其封装为Map集合
* 注意:
1.这个方法查询的结果集长度只能是1
2.如果查询的id不存在会报错,因为查询的结果集长度是0
3.如果是查询的结果集是二条以上的也会报错,因为结果集是2以上
String sql = "select * from emp where id = ? or id = ?";
Map<String, Object> map = template.queryForMap(sql, 1001,1002);
System.out.println(map);
4.如果查询的结果集是2以上,使用下一个方法
*/
@Test
public void test4(){
String sql = "select * from emp where id = ?";
Map<String, Object> map = template.queryForMap(sql, 1001);
System.out.println(map);
//{id=1001, ename=孙悟空, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=20}
}
/**
* 5. 查询所有记录,将其封装为List
将查询的每一条记录封装成一个map集合,然后在存储在list中
*/
@Test
public void test5(){
String sql = "select * from emp";
List<Map<String, Object>> list = template.queryForList(sql);
for (Map<String, Object> stringObjectMap : list) {
System.out.println(stringObjectMap);
}
}
/**
* 6. 查询所有记录,将其封装为Emp对象的List集合
*/
@Test
public void test6_2(){
String sql = "select * from emp";
//调用query方法,参数1为sql 参数2为对象(工具给我提供好的一个实现类,只需要以反射的形式把java对象传递进去即可)
List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
for (Emp emp : list) {
System.out.println(emp);
}
}
/**
* 7. 查询总记录数
*/
@Test
public void test7(){
String sql = "select count(id) from emp";
//查询的结果用queryForObject,参数2为返回的结果类型
Long total = template.queryForObject(sql, Long.class);
System.out.println(total);
}
}
注意:一般我们不会将查询出来的每一条数据封装在map集合中,然后在存储在list里,而是直接把查询出来的每一条数据封装成指定的java对象,然后在存储到list集合中
emp:注意数据类型要是对象类型(不能是int等。。)。因为如果不是对象类不能接受null的空值数据
import java.util.Date;
public class Emp {
private Integer id;
private String ename;
private Integer job_id;
private Integer mgr;
private Date joindate;
private Double salary;
private Double bonus;
private Integer dept_id;
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", ename='" + ename + '\'' +
", job_id=" + job_id +
", mgr=" + mgr +
", joindate=" + joindate +
", salary=" + salary +
", bonus=" + bonus +
", dept_id=" + dept_id +
'}';
}
}