目录
jdbc事务管理以及数据库连接池:https://blog.csdn.net/weixin_46919419/article/details/112426138
jdbc概述
数据的持久化:将数据保存在可掉电存储设备中。
方式:文件、数据库、其他
JDBC是一个独立于特定数据库管理系统,通过SQL数据区存取和操作的接口(一组api),定义了用来访问数据库标准java类库,(java.sql,javax.sql)使用这些类库可以以标准的方法、方便地访问数据库资源。
无jdbc时
使用jdbc时
两套api
面向应用,供程序员
面向数据库,供厂商
驱动:数据库厂商对oracle给出的api的实现集合——面向接口编程
快速入门
快速入门
步骤:
1、导入驱动jar包(也可以使用maven),jar包可以在mysql官网下
2、注册驱动
3、获取数据库连接对象connection
4、定义sql
5、获取执行sql语句的对象statement
6、执行sql,接受返回结果
7、处理结束
8、释放资源
导入jar包的过程
1、新建一个libs(方便管理)文件夹并将驱动jar包放入
2、右键libs
选择add as library
连接数据库具体过程
import java.sql.*;
/*
* JDBC快速入门
* 详解每个对象
1、* DriverManager:驱动管理对象
功能:
* 1、注册驱动:告诉程序该使用哪一个数据库驱动jar
* static void registerDriver(Driver driver):注册给定的驱动程序DriverManager。
* 写代码用:Class.forName("com.mysql.jdbc.Driver");//低版本写法
* 通过查看源代码发现:在com.mysql。。。中存在静态代码块
static {
try {
java.sql.DriverManager(new Driver());
}catch (SQLException E){
throw new RuntimeException("Can't register driver!");
}
}
* 注意:在5.0版本后可以不写,因为在jar包中有META-INF/services/java.sql.Driver自动注册驱动
2、获取数据库连接
*方法:static Connection getConnection(String url,String user,String password)
* 参数:
*url:指定连接的路径(mysql的方法)
*语法jdbc:mysql://ip地址(域名):端口/数据库名称
* 例子jdbc:mysql://localhost:3306/students?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
* 其中?后面是高版本要加字符集和时区其中GMT%2B8是GMT+8北京时间
* 细节:如果连接的是本机的mysql服务器且默认3306可以不写ip和端口
* user:用户名
* password:密码
* Connection:数据库连接对象
1、功能:
1、获取执行sql的对象
* Statement createStatement()
* PrepareStatement prepareStatement(String sql)
2、管理事务:
*开启事务void setAutocommit(boolean autoCommit):调用该方法设置参数为false,即开启事务也就是关闭自动提交
* 提交事务commit()
* 回滚事务rollback()
3、* Statement:执行sql的对象
1、执行sql
* boolean execute(String sql):可以执行任意的sql,用的不多了解就行
* int executeUpdate(String sql):执行DML(增删改)、DDL(创建删除修改表、库不常用)语句
返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功
*ResultSet executeQuery(String sql):执行DQL(select)语句,返回结果集对象
4、 * ResultSet:结果集对象,封装查询结果的对象
说明:通过游标取数据
boolean next()方法:游标向下移动一行
获取数据,一次只能获取某一列的数据通过getXxx(参数):获取数据,XXX表示数据类型 如 getInt、getString
参数:两种情况
1、int:代表列的编号,从1开始。如:getString(1)
2、string:代表列名称,如:getDouble("balance")
* PreparedStatement:执行sql的对象(更加强大)
1、sql注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
1、输入用户随便,输入密码a' or 'a' = 'a
2、select * from user where username='dasda' and password='a' or 'a' = 'a'
2、解决sql注入问题:使用preparedStatement对象来解决
preparedStatement是Statement的子接口,是预编译的sql
3、预编译的sql:参数使用?作为占位符
4、步骤:
//1、导入驱动jar包
//2、注册驱动
//3、获取数据库连接对象
//4、定义sql语句
注意:sql的参数使用?作为占位符。如username=? and password=?;
//5、获取执行sql的对象preparedStatement=Connection.prepareStatement(String sql)
//6、给?赋值:
1、方法:使用prepareStatement里面的方法setXxx(参数1,参数2)
参数1:?的位置从1开始
参数2:?的值
//7、执行sql,接收返回结果,不需要传递sql语句
//8、处理结果
//9、释放资源
5、注意:后期都会使用PreparedStatement来完成增删改查的所有操作
1、可以防止SQL注入
2、效率更高
* */
public class JdbcDemo1 {
public static void main(String[] args) throws Exception {//抛掉forName的异常
//1、导入驱动jar包
//2、注册驱动
//Class.forName返回与给定的字符串名称相关联类或接口的Class对象
Class.forName("com.mysql.cj.jdbc.Driver");//高版本mysql
//3、获取数据库连接对象
Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/students?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8","root","****password****");
//4、定义sql语句
String sql="delete students_information from students_information where id='180740010201';";
//5、获取执行sql的对象statement
Statement stmt= conn.createStatement();
//6、执行sql,更新表使用.executeUpdate()方法
int count= stmt.executeUpdate(sql);
//7、处理结果
System.out.println(count);
//8、释放资源
stmt.close();
conn.close();
}
}
练习
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
//练习
public class jdbcDemo2 {
public static void main(String[] args) {
//提升作用域
Statement stmt=null;
Connection conn=null;
try {
//1、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2、定义sql
String sql="insert into account values(null,'王五',3000)";
//3、获取Connection对象
conn= DriverManager.getConnection("jdbc:mysql:///db3?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8","root","****password***");
//4、获取执行sql的对象
stmt= conn.createStatement();
//5、执行sql
int count=stmt.executeUpdate(sql);//影响的行数
//6、处理结果
System.out.println(count);
if (count>0){
System.out.println("添加成功");
}else System.out.println("添加失败");
}catch (ClassNotFoundException e){
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//stmt.close()不这样写是避免空指针
//7、释放资源
if (stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
效果(这里使用的是jetbrain的datagrip查看的数据库)
修改account表前
修改后:
注意:执行DDL没有返回值
ResultSet详解
4、 * ResultSet:结果集对象,封装查询结果的对象
说明:通过游标取数据
boolean next()方法:游标向下移动一行,判断当前行是否是最后一行末尾如果是则返回false,如果不是则返回true
获取数据,一次只能获取某一列的数据通过getXxx(参数):获取数据,XXX表示数据类型 如:getInt、getString
参数:两种情况
1、int:代表列的编号,从1开始。如:getString(1)
2、string:代表列名称,如:getDouble("balance")
练习源码:
public class jdbcDemo6 {
public static void main(String[] args) {
Statement stmt=null;
Connection conn=null;
ResultSet rs=null;//ResultSet结果集对象
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn= DriverManager.getConnection("jdbc:mysql:///db3?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8","root","15971980753mjh!");
String sql="select * from account;";
stmt=conn.createStatement();
rs= stmt.executeQuery(sql);
//处理结果ResultSet版
//1、让游标向下移动一行,游标默认在第一行上面一行
rs.next();
//2、获取数据
int id=rs.getInt(1);//获取id
String name=rs.getString("name");//获取名称
double balance=rs.getDouble(3);//获取工资
System.out.println(id+"---"+name+"---"+balance);//输出获取的结果
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源,后申请先释放的原则先释放rs
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}if (stmt!=null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
结果:
ResultSet遍历结果集(真正的使用方式)
注意:使用时
使用步骤:
1、游标向下移动一行
2、判断是否有数据
3、获取数据
代码:
//1、循环判断游标是否是最后一行末尾。
while(rs.next()) {
//2、获取数据
int id = rs.getInt(1);//获取id
String name = rs.getString("name");//获取名称
double balance = rs.getDouble(3);//获取工资
System.out.println(id + "---" + name + "---" + balance);
}
查询练习
这里的Emp类是一个标准javabean,javabean定义:https://blog.csdn.net/weixin_46919419/article/details/112232192
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class jdbcDemo8 {
//查询练习
//定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回。
/*
* 1、定义emp类
* 2、定义方法public List<Emp> findAll(){}
* 3、实现方法 select *from emp;
* */
public List<Emp>findAll(){
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
List<Emp> list=null;//声明list集合
try {
//1、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2、获取连接
conn= DriverManager.getConnection("jdbc:mysql:///db3?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8","root","15971980753mjh!");
//3、定义sql
String sql="select * from emp;";
//4、获取执行sql对象
stmt =conn.createStatement();
//5、执行sql
rs=stmt.executeQuery(sql);
//6、遍历结果集,封装对象,装载集合
Emp emp=null;//为了复用引用
list=new ArrayList<Emp>();
重点部分
while (rs.next()) {
//获取数据
int id=rs.getInt("id");
String ename=rs.getString("ename");
int job_id=rs.getInt("job_id");
int mgr=rs.getInt("mgr");
Date joindate=rs.getDate("joindate");
double salary=rs.getDouble("salary");
double bonus=rs.getDouble("bonus");
int dept_id= rs.getInt("dept_id");
//创建emp对象,并赋值
emp=new Emp();
emp.setId(id);
emp.setEname(ename);
emp.setJob_id(job_id);
emp.setMgr(mgr);
emp.setJoindate(joindate);
emp.setSalary(salary);
emp.setBonus(bonus);
emp.setDep_id(dept_id);
//装载集合
list.add(emp);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt!=null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//返回集合
return list;
}
public static void main(String[] args) {
List<Emp> list= new jdbcDemo8().findAll();
System.out.println(list);
System.out.println(list.size());
}
}
效果:
简化代码JDBC工具类
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
/*
*抽取JDBC工具类:JDBCUtils
* 目的:简化书写
* 分析:
* 1、抽取注册驱动
* 2、抽取一个方法获取连接对象
* 3、抽取一个方法释放资源
* */
public class JDBCUtils {
/*静态工具类方便调用
*获取连接
*@return 连接对象
* 重点:
* 需求:不想传递参数,还得保证工具类的通用性
* 解决:配置文件
配置文件的内容:
* jdbc.properties
* url=
* user=
* password=
*/
//文件的读取,只需要读取一次即可拿到这些值,使用静态代码块
private static String url;
private static String user;
private static String password;
private static String driver;
static {
//读取资源文件,获取值
//1、创建properties集合类
Properties pro=new Properties();
try {
//获取src路径下的文件的方式--->ClassLoader 类加载器加载字节码文件进内存
//随便一个字节码文件都可以就是.class文件
ClassLoader classLoader=JDBCUtils.class.getClassLoader();
//.getResource方法:传一个文件名就可以获取该文件的resource资源(绝对路径),返回一个URL对象
//URL表示统一资源定位符
URL res=classLoader.getResource("jdbc.properties");
//注意这里项目路径不能有中文,文件夹的名字要规范
//获取字符串路径
String path= res.getPath();
//打印一下path
System.out.println(path);
//2、加载文件
pro.load(new FileReader(path));
//3、获取数据、赋值
url=pro.getProperty("url");
user=pro.getProperty("user");
password=pro.getProperty("password");
driver=pro.getProperty("driver");
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
/*
* 释放资源——update语句的资源释放
* */
public static void close(Statement stmt ,Connection conn){
if (stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/*
* 释放资源——重载用于查询语句释放资源
* */
public static void close(ResultSet rs,Statement stmt,Connection conn){
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用结果:
连接数据库
conn=JDBCUtils.getConnection();
释放资源
finally {
JDBCUtils.close(rs,stmt,conn);
}
代码格式版
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
/*
*抽取JDBC工具类:JDBCUtils
* 目的:简化书写
* 分析:
* 1、抽取注册驱动
* 2、抽取一个方法获取连接对象
* 3、抽取一个方法释放资源
* */
public class JDBCUtils {
/*静态工具类方便调用
*获取连接
*@return 连接对象
* 重点:
* 需求:不想传递参数,还得保证工具类的通用性
* 解决:配置文件
* jdbc.properties
* url=
* user=
* password=
*/
//文件的读取,只需要读取一次即可拿到这些值,使用静态代码块
private static String url;
private static String user;
private static String password;
private static String driver;
static {
//读取资源文件,获取值
//1、创建properties集合类
Properties pro=new Properties();
try {
//获取src路径下的文件的方式--->ClassLoader 类加载器加载字节码文件进内存
//随便一个字节码文件都可以就是.class文件
ClassLoader classLoader=JDBCUtils.class.getClassLoader();
//.getResource方法:传一个文件名就可以获取该文件的resource资源(绝对路径),返回一个URL对象
//URL表示统一资源定位符
URL res=classLoader.getResource("jdbc.properties");
//注意这里项目路径不能有中文,文件夹的名字要规范
//获取字符串路径
String path= res.getPath();
//打印一下path
System.out.println(path);
//2、加载文件
pro.load(new FileReader(path));
//3、获取数据、赋值
url=pro.getProperty("url");
user=pro.getProperty("user");
password=pro.getProperty("password");
driver=pro.getProperty("driver");
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
/*
* 释放资源——update语句的资源释放
* */
public static void close(Statement stmt ,Connection conn){
if (stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/*
* 释放资源——重载用于查询语句释放资源
* */
public static void close(ResultSet rs,Statement stmt,Connection conn){
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
登录练习
/*
* 练习
* 需求:
* 1、通过键盘录入用户名和密码
* 2、判断用户是否登录成功
* select * from user where username="" and password="";
* 如果这个sql有结果则成功,反之失败
* 步骤:
* 1、创建数据库表user
* */
public class jdbcDemo9 {
/*
* 登录方法
* */
public boolean login(String username,String password){
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
if (username==null||password==null){
return false;
}
//连接数据库判断是否登录成功
//1、获取连接,因为更换了数据库所以要修改配置文件,目的在于测试jdbc工具类的兼容性
try {
conn=JDBCUtils.getConnection();
//2、定义sql
String sql="select * from user where username='"+username+"' and password='"+password+"'";
//注意直接这样写会被sql注入攻击
stmt=conn.createStatement();
rs= stmt.executeQuery(sql);
//有下一行就返回true
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(rs,stmt,conn);
}
return false;
}
public static void main(String[] args) {
//1、键盘录入接受用户名和密码
Scanner sc=new Scanner(System.in);
System.out.println("输入用户名:");
String username=sc.nextLine();
System.out.println("请输入密码:");
String password=sc.nextLine();
//2、调用方法
boolean flag =new jdbcDemo9().login(username,password);
//3、判断结果,输出不同语句
if (flag){
System.out.println("登录成功");
}else System.out.println("用户名或密码错误");
}
}
效果:
//使用preparedStatement实现
public boolean login2(String username,String password){
Connection conn=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
if (username==null||password==null){
return false;
}
//连接数据库判断是否登录成功
//1、获取连接
try {
conn=JDBCUtils.getConnection();
//2、定义sql
String sql="select * from user where username=? and password=?";
System.out.println(sql);
//3、执行sql的对象
pstmt=conn.prepareStatement(sql);
//给?赋值
pstmt.setString(1,username);
pstmt.setString(2,password);
//4、执行查询,不需要传参
rs= pstmt.executeQuery();
//有下一行就返回true
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(rs,pstmt,conn);
}
return false;
}
效果: