第十一天:JDBC 连接池
1.JDBC(JAVA DATA BASE Connection):Java数据库连接
为什么会有JDBC的存在?是一种规范标准
1. 概念:Java DataBase Connectivity Java 数据库连接, Java语言操作数据库
JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
以前在DOS窗口可视化工具操作数据库,现在想用JAVA程序去操作数据库。
2.使用JDBC操作数据库步骤:
1.导入依赖Jar包
2.注册驱动
Class.forName("com.mysql.jdbc.Driver")
3.获取数据库连接对象
DriverManager.getConnection()
4.通过数据连接对象获取执行sql语句的对象--获取sql语句执行平台
connection.createStatemen()
5.定义sql语句
String sql=" sql语句";
6.执行sql语句
statement.execute(sql);
7.释放连接资源
con.close();
statement.close()
例子:
//使用JDBC操作数据库步骤
/*
* 1.导入JDBC的相关Jar包(添加依赖关系)
* 2.加载驱动(注册驱动)因为操作数据库的具体实现类是Driver类,目的是把Driver类加载进内存,加载字节码文件加载进内存
* 3.建立连接(获取操作数据库的连接对象)----DriverManager 通过DriverManager.getConnection()
* 4.通过数据库连接对象获取能够操作数据库的对象(获取能够执行sql语句的对象)--获取执行sql语句平台
* 5.定义sql语句
* 6。执行sql语句
* 7.释放资源
* */
// 1.导入JDBC的相关Jar包(添加依赖关系)
// 2.(注册驱动)
Class.forName("com.mysql.jdbc.Driver");
// 3.建立连接(获取操作数据库的连接对象)----DriverManager 通过DriverManager.getConnection()
Connection con = DriverManager.getConnection("Jdbc:mysql://localhost:3306/db5", "root", "root");
//4.通过数据库连接对象获取能够操作数据库的对象(获取能够执行sql语句的对象)--获取执行sql语句平台
Statement statement = con.createStatement();
// 5.定义sql语句
// 添加一条数据
String sql="INSERT INTO `emp1`(`id`,`NAME`) VALUES(NULL,'王五');";//双引号里面不能放双引号,可以放单引号
// 6.执行sql语句
statement.execute(sql);
优化之后:
代码:
ArrayList<Stu> stu = getStu();
for (Stu stu1 : stu) {
System.out.println(stu1);
}
}
private static ArrayList<Stu> getStu() {
//把stu对象放到ArrayList集合中去
ArrayList<Stu> stus = new ArrayList<>();
Connection con=null;
Statement stat=null;
ResultSet resultSet=null;
try {
// 1.获取数据连接
con = JDBCUtilDemo1.getConnection();
// 2.获取执行sql语句的平台(对象)
stat = con.createStatement();
//3定义sql语句
String sql="SELECT * FROM stu1;";
//4.执行sql语句 返回的是结果集 查询数据中的数据返回成一个结果集
resultSet = stat.executeQuery(sql);
//判断是否有下一个数据
// boolean next = resultSet.next(); 当next为true时证明有下一条数据
//得到下一个数据
while(resultSet.next()) {
int id = resultSet.getInt("id");//得到id字段
String name = resultSet.getString("name");
System.out.println(id+" "+name);
//创建对象
Stu stu = new Stu();
stu.setId(id);
stu.setName(name);
//把对象添加到集合中去
stus.add(stu);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtilDemo1.close(con,stat,resultSet);
}
return stus;
}
JDBC的工具类:
代码:
public class JDBCUtilDemo1 {
//提供一个获取连接对象的方法
public static Connection getConnection() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "root");
return con;
}
//关闭资源---有结果集(查询)
public static void close(Connection con, Statement stat, ResultSet res) {
//释放资源
if(con!=null){
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(stat!=null) {
try {
stat.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(res!=null){
try {
res.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//关闭资源---没有结果集(增删改)
public static void close(Connection con, Statement stat) {
//释放资源
if (con != null) {
try {
con.close();
con=null;
} catch (Exception e) {
e.printStackTrace();
}
}
if (stat != null) {
try {
stat.close();
stat=null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
结合实体类使用JDBC:
代码:
public static void main(String[] args) {
ArrayList<Student> student = getStudent();
//遍历集合
for (Student student1 : student) {
System.out.println(student);
}
}
private static ArrayList<Student> getStudent() {
ArrayList<Student> students = new ArrayList<>();
try {
Connection con = JDBCUtilDemo1.getConnection();
Statement stat = con.createStatement();
String sql="SELECT * FROM student WHERE NAME LIKE'%三%';";
ResultSet resultSet = stat.executeQuery(sql);
while (resultSet.next()){
//得到数据表中的每一个字段
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
int math = resultSet.getInt("math");
int english = resultSet.getInt("english");
Student student = new Student();
student.setId(id);
student.setName(name);
student.setAge(age);
student.setMath(math);
student.setEnglish(english);
//把对象添加到集合中去
students.add(student);
}
} catch (Exception e) {
e.printStackTrace();
}
return students;
}
细节:
static:静态的 被这个关键字修饰的会随着类的加载而加载
sql注入产生原因:
因为sql语句中存在字符串的拼接,只要给予特定的sql语句,会导致用户名与密码失效,这样的问题我们称之为sql注入
如何解决这个问题?
不使用字符串拼接,而是使用占位符 ? 进行赋值
占位符----占用位置
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
代码如下:
public static void main(String[] args) {
/*提供一个用户表 user
* 登录案列
* 键盘录入用户名与密码与数据中已存在的用户名与密码进行校验
* 如果输入的用户名与密码存在,提示“登录成功”
* 否则 提示 “登录失败”
*
* */
Scanner sc = new Scanner(System.in);
System.out.println("请输入 用户名:");
String username=sc.nextLine();
System.out.println("请输入密码:");
String password=sc.nextLine();
boolean flag = login(username, password);
if(flag)
System.out.println("登录成功");
else
System.out.println("登录失败");
}
/**
* 登录验证的方法
* @return
*/
public static boolean login(String username,String password){
try {
//获取数据库连接对象
Connection con = JDBCUtil.getConnection();
//获取执行sql语句对象
// Statement stat = con.createStatement();
//定义sql语句
// String sql="select * from user where username='"+username+"' and password='"+password+"'";
/*sql注入产生原因:
* 因为sql语句中存在字符串的拼接,只要给予特定的sql语句,会导致用户名与密码失效,这样的问题我们称之为sql注入
* 如何解决这个问题?
* 不使用字符串拼接,而是使用占位符 ? 进行赋值
* 占位符----占用位置
* */
// String sql="select * from user where username='"+username+"' and password='88' or '1'='1'";
String sql="select * from user where username=? and password=? ";
System.out.println(2);
//获取预编译对象 ---预编译sql语句,并对占位符进行赋值
// 预编译---把sql语句执行一次,让sql不能再随意更改(防止字符串拼接)
PreparedStatement pst =con.prepareStatement(sql);
System.out.println(1);
//给占位符赋值
pst.setString(1,username);
pst.setString(2,password);
System.out.println(3);
//再次真正执行sql
ResultSet resultSet = pst.executeQuery();
//执行sql语句
// ResultSet resultSet = stat.executeQuery(sql);
//进行判断 如果存在下一个元素,证明我们输入的用户名与密码与数据库中用户名和密码匹配
// resultSet.next()的返回值是boolean,如果 resultSet.next()结果为true,
// 代表存在下一个元素,意味着我们输入的用户名与密码与数据库中用户名和密码匹配
if(resultSet.next()){
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
JDBC控制事务:
1. 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
2. 操作:
1. 开启事务
2. 提交事务
3. 回滚事务
3. 使用Connection对象来管理事务
* 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
* 在执行sql之前开启事务
* 提交事务:commit()
* 当所有sql都执行完提交事务
* 回滚事务:rollback()
* 在catch中回滚事务
2.连接池:是一个容器,用来存放数据库连接的容器
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,访问数据库,用户访问玩之后,会将连接对象归还给容器。
为什么要学连接池?
连接池的好处(作用)是?
1. 节约资源
2. 用户访问高效(提高用户访问效率)
常见的连接池有:c3p0 Druid dbcp
实现:
1. 标准接口:DataSource javax.sql包下的
1. 方法:
* 获取连接:getConnection()
* 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接
2. 一般我们不去实现它,有数据库厂商来实现
1. C3P0:数据库连接池技术
2. Druid:数据库连接池实现技术,由阿里巴巴提供的
c3p0的使用:
1.导入依赖Jar包
2.导入配置文件(建议放在src下面)
3.创建连接对象(DateSource)
C3P0:数据库连接池技术
* 步骤:
1. 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar ,
* 不要忘记导入数据库驱动jar包
2. 定义配置文件:
* 名称: c3p0.properties 或者 c3p0-config.xml
* 路径:直接将文件放在src目录下即可。
3. 创建核心对象 数据库连接池对象 ComboPooledDataSource
4. 获取连接: getConnection
* 代码:
//1.创建数据库连接池对象
DataSource ds = new ComboPooledDataSource();
//2. 获取连接对象
Connection conn = ds.getConnection();
例子:
/*使用c3p0连接池操作数据库的步骤:
* 1.要导入连接池jar包
* 注意:使用连接池技术操作数据库也需要jdbc的jar
* 2.导入配置文件
* 配置文件要放在src下面(会自动加载配置文件中的内容)
*
* 3.创建连接池对象
* DateSource(接口)----ComboPooledDataSource
*
* 4.获取连接对象
*
* */
//默认使用配置文件中的 <default-config>
DataSource ds=new ComboPooledDataSource();
//获取连接对象
Connection con = ds.getConnection();
//操作数据库
//定义sql语句
String sql="select * from account where id=? or id=?";
PreparedStatement pst = con.prepareStatement(sql);
pst.setInt(1,1);
pst.setInt(2,2);
ResultSet res = pst.executeQuery();
//遍历结果集
while(res.next()){
int id = res.getInt("id");
String name = res.getString("name");
double balance = res.getDouble("balance");
System.out.println(id+"\t"+name+"\t"+balance);
}
Druid:数据库连接池实现技术,由阿里巴巴提供的
1. 步骤:
1. 导入jar包
2. 定义配置文件:
* 是properties形式的
* 可以叫任意名称,可以放在任意目录下
3. 加载配置文件。Properties
4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
5. 获取连接:getConnection
例子:
/*使用Druid连接池操作数据库步骤
1.导入jar包
2.导入配置文件(可以放在项目的任意位置,但是建议放在src下面)
3.创建连接池对象
使用DataSource的工厂类 DruidDataSourceFactory
调用createDataSource创建连接池对象
4.获取连接对象
*
*
* */
//创建流对象
/* InputStream is=new FileInputStream
("druid.properties");*/
InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
//创建Properties对象
Properties pt=new Properties();
//加载配置文件
pt.load(is);
// 3.创建连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pt);
// 4.获取连接对象
Connection con = ds.getConnection();
System.out.println(con);
//执行sql语句
}
Spring JDBC
* Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发
* 步骤:
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:查询结果,将结果封装为对象
* 一般用于聚合函数的查询
代码:
public static void main(String[] args) {
/*JDBCTemplate:
* Spring对jdbc的一个封装,Spring为操作JDBC提供的一个小的框架
* 目的:简化执行sql语句的代码书写。
* 框架是什么?相当于一个半成品软件。
* Spring1框架----用来做数据库的添加操作---小的软件
* 对数据库做 具体的添加操作时,基于 前面已经封装好的一个小的软件进行二次开发。
* 使用JDBCTemplate的步骤:
* 1.导入jar包。
* 2.创建JDBCTemplate对象 ,依赖于连接池
* JDBCTemplate提供了很多方法,用来简化执行sql语句的书写
* update()----执行增删改语句
* Query()---将查询的结果封装成实体类(JAVABean)对象
* QueryForMap()---将查询的结果封装成map集合(只能查询一条数据)
* QueryForList()---将查询的结果封装成list集合(查询一条数据或多条数据)
* QueryForObject()----一般用于聚合函数的查询
* */
//先要获取连接池对象
DataSource ds = DruidUtil.getDs();
// 2.创建JDBCTemplate对象 ,依赖于连接池
JdbcTemplate jdbcTemplate = new JdbcTemplate(ds);
String sql="insert into account values(?,?,?)";
// 操作sql语句
jdbcTemplate.update(sql,3,"老王",9000);
//使用JDBCTemplate 往account 表中添加一条数据
}
今日学习感受:学习java的路上虽然很长,但是累并快乐着,学习的东西虽然很多,但是大部分只要自己认真去学,还是可以学好的,希望自己继续坚持下去。最后一句话:生于忧患,死于安乐.