JDBC
1、基本概念
2、快速入门
package club.suhai.jdbc_demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
//JDBC快速入门
public class JdbcDem01 {
public static void main(String[] args) {
// 1.导入jar包到libs目录下
try {
Class.forName("com.mysql.jdbc.Driver");
// 3.获取数据库链接对象
try {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "0610");
// 4.定义sql语句
String sql = "update stu set age = 99 where id = 1";
// 5.获取执行sql的对象 statement
Statement statement = connection.createStatement();
// 6.执行sql
int age = statement.executeUpdate(sql);
// 7.处理结果
System.out.println(age);
// 8.释放资源
statement.close();
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
2、1 详解各个对象
1. DriverManager:驱动管理对象
1、DriverManager:驱动管理对象
功能:1.注册驱动://告诉程序该使用哪一个数据库驱动jar包
public static void registerDriver(Driver driver) throws SQLException
//使用DriverManager注册给定的驱动程序
2.获取数据库连接
public static Connection getConnection(String url,
String user, String password)
url: 指定连接路径 jdbc:mysql://localhost(域名):3306(端口号)/数据库名
user: 数据库用户名
password: 数据库用户密码
连接本地数据库:url 可以简写:jdbc:mysql:///数据库名称
2、Connection:数据库连接对象
2、Connection:数据库连接对象
1.功能:获取执行sql的对象
Statement createStatement();
PreParedStatement preparedStatement(String sql);
2.管理事务
开启事务:
void setAutoCommit(boolean autoCommit) 将此连接的自动提交模式设置为给定状态。
提交事务:
void commit() 使自上次提交/回滚以来所做的所有更改成为永久更改,并释放此 Connection对象当前持有的所有数据库锁。
回滚事务:void rollback() 撤消当前事务中所做的所有更改,并释放此 Connection对象当前持有的所有数据库锁。
3、Statement:执行sql的对象
3、Statement:执行sql的对象(不安全,实际并不会使用)
1.执行sql:
1.1 boolean execute(String sql) 执行给定的SQL语句,该语句可能返回多个结果。
1.2(常用)int executeUpdate(String sql) 执行给定的SQL语句,这可能是 INSERT , UPDATE ,或 DELETE语句,或者不返回任何内容,如SQL DDL语句的SQL语句。
参数
sql -一个SQL数据操纵语言(DML)语句,比如INSERT , UPDATE或DELETE ; 或者不返回任何内容的SQL语句,例如DDL语句。
返回结果
//(1)SQL数据操作语言(DML)语句的行数 ---判断是否执行成功
//(2)0表示不返回任何内容的SQL语句
1.3ResultSet executeQuery(String sql) 执行给定的SQL语句,该语句返回单个 ResultSet对象。
4、ResultSet:结果集对象 //封装查询结果
4、ResultSet:结果集对象 //封装查询结果
1.boolean next() 将光标从当前位置向前移动一行。
2.getXXX(参数):获取数据
// XXX代表你要获取数据的数据类型
如:
//获取结果集id
int id = resultSet.getInt(1);
//获取结果集name
String name = resultSet.getString("name");
//获取结果集acount
double acount = resultSet.getDouble(3);
参数:
int :代表列的编号,从1开始,如getString(1);
String:代表列名称,如 getDouble("account");
3.注意:
使用步骤:
1.游标向下移动一行
2.判断是否有数据
3.获取数据
//循环判断游标是否是最后一行末尾
while (resultSet.next()){
//获取结果集id
int id = resultSet.getInt(1); //参数 1 代表获取第一列的id
//获取结果集name
String name = resultSet.getString("name");//参数 name 代表获取列名为 name 的数据
//获取结果集acount
double acount = resultSet.getDouble(3);
System.out.println(id+"---"+name+"---"+acount);
}
4.小练习
//定义一个方法,查询emp表的数据,并将其封装成对象,然后装在集合,返回
4.1 定义一个emp类
4.2 定义方法 public List<Emp> findAll();
4.3 实现方法 select *from emp;
5、PreparedStatement:执行sql的对象
5、PreParedStatement:执行sql的对象
1.SQL注入问题:在拼接sql时有一些sql特殊关键字参与字符串的拼接,会造成安全性问题
1.输入用户随便,输入密码:a' or 'a' = 'a
请输入用户名:
adadad
请输入用户密码:
a' or 'a' = 'a
/E:/WorkSpace/JDBCDemo/out/production/JDBCDemo/jdbc.properties
select * from user where username = 'adadad' and password = 'a' or 'a' = 'a'
恭喜您adadad登录成功!
2.解决SQL注入问题:使用PreparedStatement对象来解决
3.预编译的sql: //参数使用?作为占位符
4.步骤
1.导入驱动jar包
2.注册驱动
3.获取数据库对象 Connection
4.定义sql
注意:// sql的参数使用?作为占位符,如 select * from user where username = ? and password = ?
5.获取执行sql语句的对象 PreParedStatement Connection.preparStatement(String sql)
6.给 ? 赋值:
方法:setXXX(参数1,参数2)
参数1:?的编号从1开始
参数2:?的值
7.执行sql ,接受返回的结果,不需要传递sql语句
8.处理结果
9.释放资源
5.注意:后期都会使用 PreParedStatement 来完成增删改查的所有操作,放弃使用statement,防止出现sql注入
2、2 抽取JDBC工具类( JDBCUtils)
目的:简化书写
分析:
-
注册驱动抽取
-
抽取一个方法获取连接对象
-
抽取方法释放资源
需求:不想传参(麻烦),还得保证工具类的通用性
解决:配置文件
jdbc.properties
url =
user =
password =
//工具类 package club.suhai.Util; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.net.URL; import java.sql.*; import java.util.Properties; /** * jdbc工具类 */ public class JdbcUtils { private static String url; private static String user; private static String password; private static String driver; /** * 文件的读取,只需要读取一次即可拿到这些值,使用静态代码块 */ static { //读取资源文件 //1.创建Properties对象 Properties properties = new Properties(); //加载文件 //获取src路径下的文件的方式:---> ClassLoader 类加载器 ClassLoader classLoader = JdbcUtils.class.getClassLoader(); URL res = classLoader.getResource("jdbc.properties"); String path = res.getPath(); System.out.println(path); try { properties.load(new FileReader(path)); } catch (IOException e) { e.printStackTrace(); } //3.获取数据,赋值 url = properties.getProperty("url"); user = properties.getProperty("user"); password = properties.getProperty("password"); driver = properties.getProperty("driver"); try { Class.forName(driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 获取连接方法 * @return连接对象 */ public static Connection getConnection() throws SQLException{ return DriverManager.getConnection(url,user,password); } /** * 释放资源 * @param resultSet * @param statement * @param connection */ public static void close(ResultSet resultSet,Statement statement, Connection connection){ if (statement!=null){ try { statement.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if (connection!=null){ try { connection.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if (resultSet!=null){ try { resultSet.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } }
//配置文件 url = jdbc:mysql:///db1 user = root password = 0610 driver = com.mysql.jdbc.Driver
//测试类 package club.suhai.jdbc_demo; import club.suhai.Util.JdbcUtils; import club.suhai.domain.Emp; import java.sql.*; import java.util.ArrayList; import java.util.List; public class jdbcDemo7 { public static void main(String[] args) { // List<Emp> list = new jdbcDemo6().findAll(); System.out.println(list); System.out.println(list.size()); } /** * 演示工具类 */ public List<Emp> findAll(){ ResultSet resultSet = null; Statement statement = null; Connection connection = null; List<Emp> list = null; //1.注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //2.获取连接 try { // connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8","root","0610"); connection = JdbcUtils.getConnection(); //3.定义sql String sql = "select* from users"; //4.获取执行sql的对象 statement = connection.createStatement(); //5。执行sql resultSet = statement.executeQuery(sql); //6.遍历结果集 Emp emp = null; //建立集合 list = new ArrayList<>(); while (resultSet.next()){ int id = resultSet.getInt("id"); String name = resultSet.getString("name"); Date birthday = resultSet.getDate("birthday"); String phone = resultSet.getString("phone"); //创建对象 emp = new Emp(); emp.setId(id); emp.setName(name); emp.setBirthday(birthday); emp.setPhone(phone); list.add(emp); } return list; } catch (SQLException throwables) { throwables.printStackTrace(); } } catch (ClassNotFoundException e) { e.printStackTrace(); }finally{ JdbcUtils.close(resultSet,statement,connection); } return list; } }
练习:
需求:
1.通过键盘录入用户名密码
2.判断用户是否登录成功
步骤:
1.创建用户数据表
create table user(
id int primary key auto_increm,
username varchar(32),
password varchar(32)
);
3、JDBC控制事务
-
事务:一个包含多个步骤的业务操作,如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败
-
操作:
- 开启事务
- 提交事务
- 回滚事务
-
使用connection对象来管理事务
-
开启事务:setAutoCommit(booleam autoCommit): 调用该方法设置参数为 false,即开启事务
在执行sql前开启事务
-
提交事务:commit();
当所有sql执行完,提交事务
-
回滚事务:rollback();
在catch中回滚事务
-
4、JDBC连接池
4、1 数据库连接池
1.概念:其实就是一个容器(集合),存放数据库连接的容器.
当系统初始化好后,容器被创建,容器中会申请一些数据库连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完后,会将连接对象归还给容器。
2.好处:
1.节约资源
2.用户访问高效
3.实现:
标准接口 :DataSource java.sql 包下的
方法: 获取连接:getConnection()
归还连接:如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接,而是归还连接。
一般我们不去实现它,有数据库厂商来实现
1. CP30: 数据库连接池技术(有点古老)
2. Druid: 数据库连接池技术,由阿里巴巴提供
4、2 C3P0
步骤:
1.导入jar包,c3p0-0.9.5.2.jar和mchange-commons-java-0.2.12.jar 别忘记导入数据库驱动jar包 mysql-connector-java-5.1.37-bin.jar
2.定义配置文件:
文件:c3p0.properties 或者 c3p0-config.xml
路径:直接将文件放在src目录下即可
3.创建核心对象 数据库连接池对象 ComboPooleDataSource
4.获取连接: getC
package club.suhai.c3po;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* c3p0演示2
*/
public class c3p0Demo2 {
public static void main(String[] args) throws SQLException {
//1.获取DataSource ,使用默认配置
DataSource dataSource = new ComboPooledDataSource();
// <!-- 超出最大连接数量(10) -->
for (int i = 1;i <= 11;i++ ) {
Connection connection = dataSource.getConnection();
System.out.println(i+":"+connection);
if (i==5){
connection.close(); //归还连接到连接池中
}
}
}
public void testNamedConfig() throws SQLException{
DataSource dataSource = new ComboPooledDataSource("otherc3p0");
for (int i = 1;i <= 11;i++ ) {
Connection connection = dataSource.getConnection();
System.out.println(i+":"+connection);
if (i==5){
connection.close(); //归还连接到连接池中
}
}
}
}
4、2 Druid
1、步骤:
1.导入jar包 druid-1.0.9.jar
2.定义配置文件:
是properties形式的
可以叫任意名称,可以放在任意目录下
3.获取数据库连接对象:通过工厂类来获取,DruidDataSourceFactory
4.获取连接:getConnection;
2、定义工具类
1.定义一个工具类DruidUtils
2.提供静态代码块加载配置文件
3.提供方法
1.获取连接方法:通过数据库连接池获取连接
2.释放资源
3.获取连接池的方法
//propterties 配置文件
driverClassName = com.mysql.jdbc.Driver
#?设置字符集
url = jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&characterEncoding=utf-8
username = root
password = 0610
#初始化连接数量
initialSize = 5
#最大连接数量
maxActive = 10
#最大等待时间
maxWait = 3000
package club.suhai.Druid;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
/**
* Druid演示
*/
public class DruidDemo {
public static void main(String[] args) throws Exception{
//
Properties pro = new Properties();
InputStream resourceAsStream = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(resourceAsStream);
DataSource dataSource = DruidDataSourceFactory.createDataSource(pro);
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
}
//提取工具类
package club.suhai.DruidUtils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
/**
* Druid工具类
*/
public class DruidUtils {
//定义成员变量
private static DataSource ds;
static {
try {
//1.加载配置文件
Properties pro = new Properties();
pro.load(DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//获取Datasource
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
/**
* 释放资源
*/
public static void close(PreparedStatement preparedStatement, Connection connection){
close(null,preparedStatement,connection);
}
/**
* 释放资源
*/
public static void close(ResultSet resultSet,PreparedStatement preparedStatement, Connection connection){
if (preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();//归还连接
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (resultSet!=null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
/**
* 获取连接池方法
* @return
*/
public static DataSource getDatasource(){
return ds;
}
}
package club.suhai.Druid;
import club.suhai.DruidUtils.DruidUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
//测试工具类
public class DruidTestUtils {
public static void main(String[] args) {
//给数据库表中添加数据
Connection connection = null;
PreparedStatement preparedStatement = null;
//1.获取连接
try {
connection = DruidUtils.getConnection();
//2.定义sql
String sql = "insert into stu values(null,?,?)";
//3.获取PreparesStatement
preparedStatement = connection.prepareStatement(sql);
//4.给sql赋值
preparedStatement.setString(1,"丁六");
preparedStatement.setDouble(2,999.00);
int i = preparedStatement.executeUpdate(); //表示影响行数,判断是否执行成功
System.out.println(i);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally{
DruidUtils.close(preparedStatement,connection);
}
}
}
5、JDBC Template
5、1 Spring JDBC
Spring JDBC 的简单封装,提供了一个JDBC Template 对象简化JDBC开发
步骤:
1.导入jar包
2.创建JDBCTemplate对象,依赖于数据源DataSource
JDBCTemplate template = new JDBCTemplate(ds);
3.调用JDBCTemplate方法来完成CRUD(增删改查)操作
update(): 执行DML语句,增删改语句
queryForMap(): 查询结果将结果集封装为Map集合
注意:Map结果集长度只能为1
queryForList():查询结果将结果集封装为List集合
注意:它是将每一条记录封装为一个一个Map集合,再把Map集合装载到List集合里面
query():查询结果,将结果集封装为 JavaBean 对象
query的参数:RowMapper
一般我们使用BeanProPertyRowMapper实现类 ,可以完成数据到JavaBean的自动封装
template.query(sql, new BeanPropertyRowMapper<类型>(类型.class));
queryForObject(): 查询结果,将结果集封装为对象
4.练习:
需求:
1.修改 1 号数据的account 为 10000.00
2.添加一条记录
3.删除刚才添加的记录
4.查询id = 1 的记录,将其封装为Map集合
注意:Map结果集长度只能为1
5.查询所有记录,将其封装为List
注意:它是将每一条记录封装为一个一个Map集合,再把Map集合装载到List集合里面
6.查询所有记录,将其封装为Emp对象的List集合
7.查询总的记录数
package club.suhai.JdbcTemplate;
import club.suhai.DruidUtils.DruidUtils;
import club.suhai.domain.Emp;
import club.suhai.domain.Emp2;
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.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class JdbcTemplateDemo2 {
//Junit单元测试 可以如方法独立执行
//放在成员变量位置,不用重复书写,私有化,不让别的类引用
private JdbcTemplate template = new JdbcTemplate(DruidUtils.getDatasource());
/**
* 1.修改 1 号数据的account 为 10000.00
*/
@Test
public void test1(){
String sql = "update users set account = 5000.00 where id = ?";
int count = template.update(sql,1);
System.out.println(count);
}
/**
* 2.添加一条记录
*/
@Test
public void test2(){
String sql = "insert into users (id,name,account,phone) values (?,?,?,?)";
int count = template.update(sql,6, "丁流",1000.00, "1111");
System.out.println(count);
}
/**
* 3.删除刚才添加的记录
*/
@Test
public void test3(){
String sql = "delete from users where id = ?";
int count = template.update(sql,6);
System.out.println(count);
}
/**
* 4.查询id = 1 的记录,将其封装为Map集合
*/
@Test
public void test4(){
String sql = "select *from users where id = ?";
Map<String,Object> map = template.queryForMap(sql,1);
System.out.println(map);
}
/**
* 5.查询所有记录,将其封装为List
*/
@Test
public void test5(){
String sql = "select *from users";
List<Map<String, Object>> list = template.queryForList(sql);
System.out.println(list);
}
/**
* 6.查询所有记录,将其封装为Emp对象的List集合
*/
@Test
public void test6(){
String sql = "select *from users";
List<Emp2> list = template.query(sql, new RowMapper<Emp2>() {
@Override
public Emp2 mapRow(ResultSet resultSet, int i) throws SQLException {
Emp2 emp2 = new Emp2();
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
double account = resultSet.getDouble("account");
String phone = resultSet.getString("phone");
emp2.setId(id);
emp2.setName(name);
emp2.setAccount(account);
emp2.setPhone(phone);
return emp2;
}
});
for (Emp2 emp : list) {
System.out.println(emp);
}
}
/**
* 7.查询总的记录数
*/
@Test
public void test7(){
String sql = "select *from users";
List<Emp2> list = template.query(sql, new BeanPropertyRowMapper<Emp2>(Emp2.class));
for (Emp2 emp :list ) {
System.out.println(emp);
}
}
}