一.java 数据库连接 JDBC
1.全称:jdbc:
java database connectivity
直译:java 数据库连接
2.表面意思:java连接并操作数据库 -- 解释jdbc是干什么的
3.本质含义:jdbc是sun公司制定的一套连接关系型数据库需要遵循的规范,即接口。而各个关系型数据库厂商自己来实现这个接口。程序员只需要面向接口编程。解释jdbc如何实现连接并操作数据库的.
即:jdbc通过定义了一些接口,借助接口中定义的抽象方法,来规定java要如何连接数据库,如何操作数据库。而接口中的抽象方法的具体实现,会因为数据库的不同实现方式也不一样,但是这个不是我们关心的,因为这些实现类是数据库厂商提供的,我们只需会调用接口中的方法就可以了
2.快速入门
- 入门小案例
public class Hello3 {
private Connection con;
private Statement state=null;
private ResultSet rs=null;
@Before //创建链接
public void init(){
try {
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/db1";
con= DriverManager.getConnection(url,"root","123456");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test //查询
public void test1(){
Statement state=null;
ResultSet rs=null;
try {
//定义sql
String sql="select * from emp";
//获取执行sql的对象
state = con.createStatement();
//执行sql 返回一个结果集合rs--集合加上迭代器
rs = state.executeQuery(sql);
ArrayList<Emp> emps = new ArrayList<>();
while (rs.next()){
int id=rs.getInt("id");
String name = rs.getString("NAME");
String gender = rs.getString("gender");
double salary = rs.getDouble("salary");
Date join_date = rs.getDate("join_date");
int dept_id=rs.getInt("dept_id");
//调用有参构造
Emp emp = new Emp(id,name,gender,salary,join_date,dept_id);
emps.add(emp);//对象装到集合中
}
System.out.println(emps);
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源 倒关
if(rs != null){
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(con != null){
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(state != null){
try {
state.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@After
public void closeResources(){
if(rs != null){
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(con != null){
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(state != null){
try {
state.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
总结流程
:
导入jar包
加载驱动
构建连接对象
生成statement对象
执行sql
处理结果
释放资源
3.核心类详解
3.1 DriverManager
- 两个功能
1. 管理和注册驱动:查看源码解释
2. 获取连接对象
- 获取连接对象的方法
public class Hello1 {
@Test //入门案例---获取连接对象 方式3
public void test3(){
try{
//1.注册驱动 Driver
Class.forName("com.mysql.jdbc.Driver");
//2.DriverManager 获取连接数据库对象
String url = "jdbc:mysql://localhost:3306/shop";
//3.使用类加载器加载jdbc.properties文件,返回一个字节流,和Properties关联在一起
InputStream is = Hello1.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties p = new Properties();
p.load(is);
Connection con = DriverManager.getConnection(url,p);
System.out.println(con);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test //入门案例---获取连接对象 方式2
public void test2(){
try {
//1.注册驱动 Driver
Class.forName("com.mysql.jdbc.Driver");
//2.DriverManager 获取连接数据库对象
String url = "jdbc:mysql://localhost:3306/shop";
//3.创建 Properties对像
Properties p = new Properties();
p.setProperty("user","root");
p.setProperty("password","123456");
Connection con = DriverManager.getConnection(url,p);
System.out.println(con);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test //入门案例---获取连接对象 方式1
public void test1(){
try {
//1.注册驱动 Driver
Class.forName("com.mysql.jdbc.Driver");
//2.DriverManager 获取连接数据库对象
String url = "jdbc:mysql://localhost:3306/shop";
Connection con = DriverManager.getConnection(url, "root", "123456");
System.out.println(con);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 连接数据库四大参数
1.
驱动类的字符串名
:com.mysq.jdbc.Driver – 在jar文件的META-INF/services文件夹下
2.
连接协议路径字符串url
:不同的数据库url是不同的,mysql的写法
jdbc:mysql://localhost:3306/数据库名[?参数名=参数值]
3.
数据库用户名
:root
4.
数据库登录密码
:123456
- url 是什么?
-
是一个连接数据库的路径,用于标识数据库的位置
-
包含:jdbc协议,mysql子协议,数据库所在主机名,数据库服务器的端口号,数据库名
-
如果是本地服务器,端口号是3306,可简写:
jdbc:mysql:///数据库名
- 乱码处理
- 如果使用jdbc对数据库进行操作时出现中文乱码,可以在url后指定字符集编码参数,表示让数据库以UTF-8编码来处理数据
jdbc:mysql:///数据库?characterEncoding=utf8
- mysql8还需要指定时区
jdbc:mysql:///数据库名?useSSL=false&serverTimezone=UTC&characterEncoding=utf8
- 案例
@Test //入门案例---获取连接对象
public void test2(){
try {
//1.注册驱动 Driver
Class.forName("com.mysql.jdbc.Driver");
//2.DriverManager 获取连接数据库对象
String url = "jdbc:mysql://localhost:3306/shop";
//3.创建 Properties对像
Properties p = new Properties();
p.setProperty("user","root");
p.setProperty("password","123456");
Connection con = DriverManager.getConnection(url,p);
System.out.println(con);
} catch (Exception e) {
e.printStackTrace();
}
}
3.2 Connection
Connection是一个接口
,具体的实现类由数据库厂商提供实现,代表一个连接对象
- 功能:
- 获取执行sql 的对象
Statement createStatement()
PreparedStatement prepareStatement(String sql) //预编译对象,效率更高
3.3 Statement
-
功能:
用于发送sql语句给服务器,用于执行静态sql语句并返回结果
-
方法
//用于发送dml语句,执行增删改的操作,返回对数据库影响的行数,还可以执行ddl语句
int executeUpdate(String sql)
//用于发送dql语句,执行查询的操作,返回结果集对象
ResultSet executeQuery(String sql)
- 释放资源
1.需要释放的对象
ResultSet
Statement
Connection
2.释放原则:先开的后关,后开的先关
ResultSet --> Statement --> Connection
3.放在finally
代码块中
finally {
//释放资源 倒关
if(rs != null){
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(con != null){
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(state != null){
try {
state.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.5 ResultSet
-
作用:
封装数据库查询的结果集,并提供了遍历结果集的方法,取出每一条记录
-
方法
boolean next() -- 每调用一次,行光标向下移动1行,返回true表示还有下一条记录,否则返回false
数据类型 getXxx() 可以通过列名或列号获取某一行的某一列的数据
- 代码演示---------查询员工表,并封装结果集到list集合中
/**
* 查询所有emp对象
* @return
*/
public List<Emp> findAll(){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
List<Emp> list = null;
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
//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.setDept_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;
}
- 核心步骤:
1.获得连接对象
2.执行查询
3.封装查询结果集
二.jdbc使用
- 工具类
- 工具类的作用:
1.实现注册驱动 和 连接对象的获取
2.释放资源
JDBC工具类
/**
* JDBC工具类
*/
public class JdbcUtil {
private static Connection con;
private static Properties p;
/**
* 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块
*/
static{
//读取资源文件,获取值。
try {
FileInputStream is = new FileInputStream("day05-web/src/jdbc.properties");
p = new Properties();
p.load(is);
System.out.println(is);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接
* @return 连接对象
*/
public static Connection getConnection() {
try {
return DriverManager.getConnection(p.getProperty("url"),p);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* 释放资源
* @param stmt
* @param conn
*/
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();
}
}
}
}
- 登录案例
public class Hello1 {
private Connection conn;
private Statement stmt;
private ResultSet rs;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的用户名:");
String name = sc.next();
System.out.println("请输入您的密码:");
String psw = sc.next();
//boolean isLogin=login1(name,psw);
boolean isLogin=login2(name,psw);
System.out.println(isLogin);
}
private static boolean login1(String name, String psw) {
if(name == null || psw == null){
System.out.println("null");
return false;
}
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
//获取连接对象
try {
conn = JdbcUtil.getConnection();
//定义sql
String sql1 = "select * from users where name = '"+name+"' and psw = '"+psw+"'";
System.out.println(sql1);
//获取执行sql对象
stmt=conn.createStatement();
System.out.println(name);
System.out.println(psw);
//执行
rs=stmt.executeQuery(sql1);
return rs.next();//如果有下一行,则返回true
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
return false;
}
//预编译对象优化登录案例
private static boolean login2(String name, String psw){
if(name == null || psw == null){
System.out.println("null");
return false;
}
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
//获取连接对象
try {
conn = JdbcUtil.getConnection();
//定义sql
String sql1 = "select * from users where name= ? and psw= ? ";
System.out.println(sql1);
//获取执行sql对象
pstm=conn.prepareStatement(sql1);
//之占位符赋值
pstm.setString(1,name);
pstm.setString(2,psw);
//System.out.println(name);
//System.out.println(psw);
//执行
rs=pstm.executeQuery();
return rs.next();//如果有下一行,则返回true
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, pstm, conn);
}
return false;
}
}
- 管理事务:
- 开启事务:
setAutoCommit(boolean autoCommit)
:调用该方法设置参数为false,即开启事务
- 提交事务:
commit()
try的最后一行
- 回滚事务:
rollback()
放在catch代码块
public class Hello2 {
public static void main(String[] args) {
//获取连接对象
Connection con=JdbcUtil.getConnection();
//定义sql
String sql1="update account set balance=balance-? where id=?";
String sql2="update account set balance=balance+? where id=?";
//获取执行sql对象
PreparedStatement ps1=null;
PreparedStatement ps2=null;
try {
//开启事务管理 --- 设置手动提交
con.setAutoCommit(false);
ps1=con.prepareStatement(sql1);
ps2=con.prepareStatement(sql2);
//赋值
ps1.setDouble(1,500);
ps1.setInt(2,1);
ps2.setDouble(1,500);
ps2.setInt(2,2);
//执行sql
ps1.executeUpdate();
//主动制造异常
//int i=7/0;
ps2.executeUpdate();
//提交事务
con.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
//回滚事务
con.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}finally {
JdbcUtil.close(null,ps1,con);
}
}
}
记得给占位符?赋值
- 两种实现方式的差异:
1.
sql语句不再是拼接参数 ,使用?代替参数
2.
在创建stmt对象时,空参 ; 在创建pstm对象时,传入sql模板 --预编译
3.
pstm对象还需要为?填充参数值
4.
stmt对象执行sql时,需要传入sql ; pstm对象执行sql时,不用再传sql
优点:
1.PreparedStatement对象可以防止sql注入,Statement对象不可以
2.PreparedStatement对象是预编译方式执行sql,会提前检查sql是否有语法错误,因此执行效率更高