JDBC
常用的包&接口
java.sql:JDBC 操作的时候,数据库相关的接口和类。
javax.sql:扩展包,可以提供额外的功能:连接池。
驱动包:mysql-connector-java-5.1.48.jar 一般都是厂家提供,厂家针对 JDBC 规范提供出来的接口, 进行实现。都是写好的 Java 源码。(https://dev.mysql.com/downloads/connector/j/)
DriverManager:主要用来管理和注册驱动,获取数据库连接对象。
Connection 接口:负责与数据库进行连接
Statement 接口:执行者对象,主要把 SQL 语句发送到数据库进行交互。
PreparedStatement 接口:执行者对象,Statement 的子类,更安全。
ResultSet 接口:用来封装从数据库中获得的数据,进而可以将数据封装到 JavaBean。
JDBC的注册和连接
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBCDemo1 {
//项目创建成功后
//项目右键选择new-》folder》创建目录lib
//把mysql驱动包复制到lib目录xia
//右键mysql驱动文件 点击buildepath=》add build path 加载jar包到项目中
//这样才可以使用这个jar包文件
//建立连接
//1.第一步 注册驱动
//2. 得到建立连接对象(Connection) 驱动管理对象中的方法得到连接对象
//3.需要传入三个参数 第一个参数url 包含了协议 本地ip端口号 指定数据库
// 参数2 用户名 参数3 密码
public static void main(String[] args) {
//第一步注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//三个参数
//URL
String url="jdbc:mysql://localhost:3306/mybase02";
//用户名
String user="root";
//密码
String password="root";
try {
//第二步 得到建立连接对象
Connection c1=DriverManager.getConnection(url, user, password);
System.out.println();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//错误:1.Unknown database \'stu\' 没有名字叫stu的数据库
//2.conection refused connet 服务未启动 或者端口号错误连接失败
//3.classnotfoundException :com.mysql.jdbc.Drvier 没有找到jar包 找到不到这个类
//4.Access.... user ‘root’ @‘localhost’(using password:YEs) 用户名密码不正确
}
}
Connection接口
Connection 主要是数据库连接对象。调用 createStatement() 方法,可以获得执行者对象,发送 SQL 到数据库执行。
Statement 执行者接口
PreparedStatement 执行者子类接口
如果使用了 PreparedStatement 类,首先会将你的 SQL 发送到数据库中进行预编译动作,然后会直接
引用预编译之后的结果,如果你的 SQL 需要传递参数的话,也可以多次传入不同的参数给这个对象并
执行。
不管有多少条 SQL 插入语句,数据库只需要预编译一次即可,可以传入多次参数,并执行。这里主要
是减少了预编译的次数,提高了执行的效率。
JDBC使用示例程序
这里我们把注册连接功能和关闭连接功能进行了封装,首先封装如下:
package utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCUtils {
//因为每次操作都需要连接数据库这一步骤 所以我们可以把这部分内容封装成工具类
//书写一个方法 方法的返回类型 connection对象
//把参数声明常量
public static final String JDBCDRVIER="com.mysql.jdbc.Driver";
public static final String URL="jdbc:mysql://localhost:3306/mybase01";
public static final String USER="root";
public static final String PASSWORD="root";
//注册驱动 放到静态代码块中 只注册一次
static {
try {
Class.forName(JDBCDRVIER);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println(getConnection());
}
public static Connection getConnection() {
try {
return DriverManager.getConnection(URL, USER, PASSWORD);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
//关闭资源
public static void closeJDBC(Connection c1,Statement s1,ResultSet rs) {
if(c1!=null) {
try {
c1.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(s1!=null) {
try {
s1.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(rs!=null) {
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
随后我们按照数据库中每一行的格式,构建相应的对象,并重写相关的tostring方法
package Bean;
//classes表的实体类
public class Classes {
//基本类型封装 使用他的引用类型类(包装类)
private Integer id;
//例如存储学生成绩 0分 缺考 int null
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Classes [id=" + id + ", name=" + name + "]";
}
}
最后我们使用junit进行简单的JDBC运行。
package com.kkb2;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import org.junit.Test;
import Bean.Classes;
import utils.JDBCUtils;
public class JDBCDemo1 {
//查询
@Test
public void fun1() throws Exception {
//第一步 建立连接
Connection c1=JDBCUtils.getConnection();
System.out.println(c1);
//区别 :
//statement: 执行静态sql语句,每次执行语句数据库都要执行sql的编译操作
//效率低下 并且有参数的时候还需要去拼接字符串就很麻烦 不能防止sql注入
//preparedstatement:执行动态sql语句 ,预编译sql语句,执行效率高,安全好
//可以防止sql注入 代码可读性高 有参数的时候可以使用占位符更方便
//select * from user where username=张三 and password=1234 or 1=1
//第二步 书写sql语句
String sql="select * from classes";
//第三步 得到执行sql对象 statement preparedstatement(重点)
PreparedStatement prepareStatement = c1.prepareStatement(sql);
//第四步 得到数据库中查询的数据
// 执行查询操作并返回结果 必须使用结果集接收
ResultSet rs = prepareStatement.executeQuery();
System.out.println(rs);
while(rs.next()) {
//第一种 列名 虽然getstring能得到其他类型数据建议使用自己类型 建议使用列名
//例如int getInt方法
// double getDouble
System.out.println("列名"+rs.getString("id"));
System.out.println("列名"+rs.getString("name"));
//第二种 放置 列号
System.out.println("列号"+rs.getInt(1));
System.out.println("列号"+rs.getString(2));
//
}
//释放资源
JDBCUtils.closeJDBC(c1, prepareStatement, rs);
}
//添加
@Test
public void fun2() throws Exception {
//第一步 建立连接
Connection c1=JDBCUtils.getConnection();
//第二步 书写sql语句
String sql="insert into classes values(11,\'十一班\')";
//第三步 得到sql执行对象 并传入sql字符串
PreparedStatement ps = c1.prepareStatement(sql);
//第四步 查看结果
int rows=ps.executeUpdate();
if(rows>0) {
System.out.println("添加成功!");
System.out.println(rows);
}
//释放资源
JDBCUtils.closeJDBC(c1,ps, null);
}
//修改
@Test
public void fun3() throws Exception {
//第一步 建立连接
Connection c1=JDBCUtils.getConnection();
//第二步 书写sql语句
String sql="update classes set name=\'11班\' where id=11";
//第三步 得到sql执行对象 并传入sql字符串
PreparedStatement ps = c1.prepareStatement(sql);
//第四步 查看结果
int rows=ps.executeUpdate();
if(rows>0) {
System.out.println("修改成功!");
System.out.println(rows);
}
//释放资源
JDBCUtils.closeJDBC(c1,ps, null);
}
//删除
@Test
public void fun4() throws Exception {
//第一步 建立连接
Connection c1=JDBCUtils.getConnection();
//第二步 书写sql语句
String sql="delete from classes where id=11";
//第三步 得到sql执行对象 并传入sql字符串
PreparedStatement ps = c1.prepareStatement(sql);
//第四步 查看结果
int rows=ps.executeUpdate();
if(rows>0) {
System.out.println("删除成功!");
System.out.println(rows);
}
//释放资源
JDBCUtils.closeJDBC(c1,ps, null);
}
//删除升级版 参数使用占位符
@Test
public void fun41() throws Exception {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入您要删除的班级id:");
int id=scanner.nextInt();
//第一步 建立连接
Connection c1=JDBCUtils.getConnection();
//第二步 书写sql语句 预编译对象 有参数时 用占位符去拼接 ?
String sql="delete from classes where id=?";
//第三步 得到sql执行对象 并传入sql字符串
PreparedStatement ps = c1.prepareStatement(sql);
//使用ps 里面的方法 可以给占位符赋值
ps.setInt(1, id);
//第四步 查看结果
int rows=ps.executeUpdate();
if(rows>0) {
System.out.println("删除成功!");
System.out.println(rows);
}
//释放资源
JDBCUtils.closeJDBC(c1,ps, null);
}
//模拟登陆案例
@Test
public void fun5() throws Exception {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入您的用户名:");
String name=scanner.next();
System.out.println("请输入您的密码:");
String pwd=scanner.next();
//第一步 建立连接
Connection c1=JDBCUtils.getConnection();
//第二步 书写sql语句 预编译对象 有参数时 用占位符去拼接 ?
String sql="select * from user where username=? and password=?";
//第三步 得到sql执行对象 并传入sql字符串
PreparedStatement ps = c1.prepareStatement(sql);
//使用ps 里面的方法 可以给占位符赋值 从1
ps.setString(1, name);//1 参数就是给第一个占位符赋值
ps.setString(2, pwd);//给第二个占位符赋值
//第四步 查看结果 现实生活中用户名是唯一 查询登陆正常返回一条语句
//我们知道结果只有一条语句 遍历的时候 可以使用if效率更高
//ps.executeQuery(sql);
//注意 无参executeQuery();
ResultSet rs = ps.executeQuery();
if(rs.next()) {
System.out.println("登陆成功"+rs.getString("username"));
}
//释放资源
JDBCUtils.closeJDBC(c1,ps, null);
}
//classes 表查询 升级版 根据id查询
//表在java工程中的实体类只实例化对象只能存储一条数据
//如果我们结果是多条怎么办? 使用集合解决我们问题 集合泛型是实体类型
@Test
public void fun6() throws Exception {
Classes cc1=new Classes();
Scanner scanner=new Scanner(System.in);
System.out.println("请输入您要查询班级的id:");
int id=scanner.nextInt();
//第一步 建立连接
Connection c1=JDBCUtils.getConnection();
String sql="select * from classes where id=?";
//第三步 得到执行sql对象 statement preparedstatement(重点)
PreparedStatement prepareStatement = c1.prepareStatement(sql);
prepareStatement.setInt(1, id);
//第四步 得到数据库中查询的数据
// 执行查询操作并返回结果 必须使用结果集接收
ResultSet rs = prepareStatement.executeQuery();
if(rs.next()) {
cc1.setId(rs.getInt("id"));
cc1.setName(rs.getString("name"));
}
System.out.println(cc1);
System.out.println(cc1.getName());
System.out.println(cc1.getId());
}
//查询classes多条数据 使用集合封装数据
@Test
public void fun7() throws Exception {
//声明集合 存储多个数据
List<Classes> list=new ArrayList<Classes>();
//第一步 建立连接
Connection c1=JDBCUtils.getConnection();
String sql="select * from classes";
//第三步 得到执行sql对象 statement preparedstatement(重点)
PreparedStatement prepareStatement = c1.prepareStatement(sql);
//第四步 得到数据库中查询的数据
// 执行查询操作并返回结果 必须使用结果集接收
ResultSet rs = prepareStatement.executeQuery();
while(rs.next()) {
Classes cc1=new Classes();
cc1.setId(rs.getInt("id"));
cc1.setName(rs.getString("name"));
list.add(cc1);
}
System.out.println(list);
}
}
jdbc的事务回滚操作
同样,我们也利用上面封装好的JDBC工具程序:
package jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import util.JDBCUtils;
//模拟转账案例
public class JDBCDemo1 {
//一个账户减钱 另一个账户加钱
//通过sql语句 其实执行修改语句 根据账户id 去修改表中金额
public static void main(String[] args) {
//第一步 建立连接
Connection c1 = JDBCUtils.getConnection();
PreparedStatement ps=null;
try {
c1.setAutoCommit(false);
//第二步 书写sql语句 10010 要给10086 转500块
String sql="update bankcard set money=money-500 where id=10010";
//第三步 得到执行sql对象 并把SQL语句传入
ps= c1.prepareStatement(sql);
int rows = ps.executeUpdate();
if(rows>0) {
System.out.println("10010减钱成功");
System.out.println(rows);
}
//
// int i=1/0;
//10086加钱
String sql2="update bankcard set money=money+500 where id=10086";
ps=c1.prepareStatement(sql2);
int rows3=ps.executeUpdate();
if(rows3>0) {
System.out.println("10086加钱成功");
System.out.println(rows3);
}
c1.commit();
System.out.println("提交事务");
} catch (Exception e) {
//事务回滚
try {
c1.rollback();
System.out.println("转账失败");
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally {
//关闭资源
JDBCUtils.closeJDBC(c1, ps, null);
}
}
}