JDBC概述
JDBC(Java DataBase Connectivity)
是一种用于执行SQL语句的 Java API
,是Java
和数据库
之间的一个桥梁,是一个规范而不是一个实现,能够交给数据库执行SQL语句。
JDBC的组成
JDBC
是由一组用Java语言编写的类和接口组成,主要有如下几个部分
-
驱动管理;
-
Connection
接口; -
Statement
接口; -
ResultSet
接口;
Connection 接口
定义:在 JDBC 程序中用于代表数据库的连接,是数据库编程中最重要的一个对象,客户端与数据库所有的交互都是通过connection 对象完成的
Connection conn = DriverManager.getConnection(url,user,password);
常见方法:
-
createStatement() :创建向数据库发送的sql的statement对象。
-
prepareStatement(sql) :创建向数据库发送预编译sql的PrepareSatement对象。
-
prepareCall(sql) : 创建执行存储过程的callableStatement对象。(常用)
-
setAutoCommit(boolean autoCommit) : 设置事务是否自动提交。
//关闭自动提交事务 setAutoCommit(false); //关闭后需要手动打开提交事务
-
commit() : 在链接上提交事务。
-
rollback() : 在此链接上回滚事务。
Statement 接口
statement
: 由createStatement
创建,用于发送简单的SQL语句(不带参数).
Statement st = conn.createStatement();
PreparedStatement
:继承自Statement接口,是Statement的子类,可发送含有参数的SQL语句。效率更高,并且可以防止SQL注入,建议使用
。
PreparedStatement ps = conn.prepareStatement(sql语句);
PreparedStatement
的优势:
Statement
会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。PreparedStatement
可对SQL进行预编译,从而提高数据库的执行效率。- 并且
PreperedStatement
对于sql中的参数,允许使用占位符的形式进行替换,简化sql语句的编写,可以避免SQL注入的问题。
CallableStatement
:继承自PreparedStatement
接口,由方法prepareCall
创建,用于调用存储过程。
常见方法:
-
executeQuery(String sql) :用于向数据发送
查询语句
。 -
executeUpdate(String sql) :用于向数据库发送insert、update或delete语句。
-
execute(String sql):用于向数据库发送任意sql语句。
-
addBatch(String sql):把多条sql语句放到一个批处理中。
executeBatch():向数据库发送一批sql语句执行
ResultSet 接口
ResultSet
:用于代表Sql语句的执行结果。
Resultset封装执行结果时,采用的类似于表格的方式,ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next()
方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。
常用方法:
ResultSet.next()
:移动到下一行;ResultSet.Previous()
:移动到前一行ResultSet.absolute(int row)
:移动到指定行ResultSet.beforeFirst()
:移动resultSet
的最前面ResultSet.afterLast()
:移动resultSet
的最后面
面向过程的实现过程
1.在pom.xml中引入mysql的驱动文件
<!-- 引入MySql的驱动文件 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
2.加载驱动类
Class.forName("com.mysql.cj.jdbc.Driver");
3.建立Java同数据库中间的连接通道
String url = "jdbc:mydql://locallhost:3306/test";//test是数据库名称
String user = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,user,password);
4.产生负责’传递命令’的‘传令官’对象
String sql ="insert into emp values(null,"苏醒","歌手",7956,now(),79429,6799,30,1)";
PrepareStement ps = conn.prepareStement(sql);
5.接收结果集(只有查询有结果集)
int row = ps.excuteUpdate();//交由MySQL执行命令
System.out.println(row + "行受到影响!");
6.关闭连接通道
ps.close();
conn.close();
参数的传递方式
//键盘赋值
private static Scanner scan;
static{
scan = new Scanner(System.in);
}
拼接字符串方式
String sql = "insert into emp values(null ,'" + ename + "','" + job + "'," + mgr + ",now()," + sal + "," + comm + "," + deptNo + ",1)";
PrepareStement ps = conn.prepareStement(sql);
//接收结果集
int row = ps.excuteUpdate();//交由MySQL执行命令
System.out.println(row + "行受到影响!");
ps.close();
conn.close();
占位符方式 ‘?’
//插入
String sql = "insert into emp values(null,?,?,?,now(),?,?,?,1)";
PrepareStement ps = conn.prepareStement(sql);
//给 ? 占位符赋值, 从1开始 具体数据类型,具体赋值 int String double
ps.setString(1,需要赋值的列);//需要几个列,附几个值
//接收结果集
int row = ps.excuteUpdate();//交由MySQL执行命令
System.out.println(row + "行受到影响!");
ps.close();
conn.close();
//注意异常处理
使用占位符的好处:
- 可以有效避免SQL注入问题
- 可以自动根据复制时的数据类型来决定是否引入"
删除:
物理删除
//完全删除,不可恢复
Connection conn = DriverManager.getConnection(url, user, password);
//删除语句
//开始产生运行处理MySQl命令的对象
String sql = "delete from emp where empno =" + 4;
PreparedStatement ps = conn.prepareStatement(sql);
逻辑删除
//修改(update)状态,不会完全删除信息,可以恢复
String sql = "update emp set state =0 where empno =?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 7953);
查询操作
全查询
String sql = "select * from emp where state=1";
PreparedStatement ps = conn.prepareStatement(sql);
// 查询会返回结果集 rs就是查询出来的那张虚拟表
ResultSet rs = ps.executeQuery();
// 虚拟表格遍历出来
while (rs.next()) { // 是否有下一行
// 如果有下一行,就会执行这里的代码 rs就是下一行
// 获取到当前行(rs)的每一列信息
int empNo = rs.getInt(1);
String ename = rs.getString(2);
String job = rs.getString(3);
int mgr = rs.getInt(4);
String hireDate = rs.getString("hireDate");
double sal = rs.getDouble(6);
double comm = rs.getDouble(7);
int deptNo = rs.getInt("deptNo");
System.out.print("编号:" + empNo+"、");
System.out.print("姓名:" + ename+"、");
System.out.print("职位:" + job+"、");
System.out.print("上司ID:" + mgr+"、");
System.out.print("入职时间:" + hireDate+"、");
System.out.print("工资:" + sal+"、");
System.out.print("奖金:" + comm+"、");
System.out.println("部门编号:" + deptNo);
}
rs.close();
ps.close();
conn.close();
}
按ID查询
String sql = "select * from emp where state=1 and empno=" + id;
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
int empNo = rs.getInt(1);
String ename = rs.getString("ename");
String job = rs.getString("job");
int mgr = rs.getInt(4);
String hireDate = rs.getString(5);
double sal = rs.getDouble("sal");
double comm = rs.getDouble(7);
int deptNo = rs.getInt(8);
//存放在容器中
Map<String, Object> map = new HashMap<>();
map.put("empNo", empNo);
map.put("ename", ename);
map.put("job", job);
map.put("mgr", mgr);
map.put("hireDate", hireDate);
map.put("sal", sal);
map.put("comm", comm);
map.put("deptNo", deptNo);
return map;
}
return null;
}
面向对象(JDBC)的实现方式
面向对象是指将多个功能查分成多个包进行对数据库的增删改查(CRUD)操作。
db
包作用
db包中只需要一个类–>DBManager
类,这个类的主要作用就是负责管理数据的的连接
//负责管理数据库的连接
public class DBManager{
/*
*/
private satic Connection getConnection(){
Connection conn = null;
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root";
conn = DriverManager.getConnection(url,uesr,password);
}
}
bean
包作用
一般和数据库中的表对应,bean包中的类一般都和表名相同,首字母大写,驼峰命名。
@Data
//模拟数据库中表的操作
//定义属性:成员变量:封装类,局部变量:原始数据类型
public class Emp {
private Integer empNo;
private String ename;
private String job;
private Integer mgr;
private String hireDate;
private Double sal;
private Double comm;
private Integer deptNo;
private Integer state;
//多表联查
//方法一:
private String dname;
private String loc;
//另一种写法
private Dept dept;
}
dao
包作用
DAO是Data Access Object数据访问接口,一般以bean包的类名为前缀,以DAO结尾,负责执行CRUD操作,一个dao类负责一个表的CRUD,也可以说成是对一个bean类的CRUD(增删改查)
public class EmpDAO(){
// 一般对于删除操作,都是进行更新状态将之隐藏
public void delete(int id){
try{
conn = DBManager.getConnection();
String sql = "update emp set state = 0 where empNo = "+ id;
ps = conn.prepareStatement(sql);
ps.executeUpdate();
}catch(ClassNotFoundException e){
e.printStackTrace();
}catch(SQLException e){
e.printStackTrace();
}finally{
DBManager.closeConn(conn, ps);
}
}
//存储
public void save(Emp emp) {
try {
conn = DBManager.getConnection();
String sql = "insert into emp values(null,?,?,?,now(),?,?,?,1)";
ps = conn.prepareStatement(sql);
ps.setString(1, emp.getEname());
ps.setString(2, emp.getJob());
ps.setInt(3, emp.getMgr());
ps.setDouble(4, emp.getSal());
ps.setDouble(5, emp.getComm());
ps.setInt(6, emp.getDeptNo());
ps.executeUpdate();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBManager.closeConn(conn, ps);
}
}
//更新--修改
public void update(Emp emp) {
try {
conn = DBManager.getConnection();
String sql = "update emp set ename=?,job=?,mgr=?,sal=?,comm=?,deptNo=? where empNo=?";
ps = conn.prepareStatement(sql);
ps.setString(1, emp.getEname());
ps.setString(2, emp.getJob());
ps.setInt(3, emp.getMgr());
ps.setDouble(4, emp.getSal());
ps.setDouble(5, emp.getComm());
ps.setInt(6, emp.getDeptNo());
ps.setInt(7, emp.getEmpNo());
ps.executeUpdate();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBManager.closeConn(conn, ps);
}
}
//单条信息查询--按ID查询--将填写的信息填写在emp属性里中,然后将emp
public Emp findEmpByNo(int id) {
Emp emp = new Emp();
try {
conn = DBManager.getConnection();
String sql = "select * from emp where empno=? and state = 1";
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
rs = ps.executeQuery();
if (rs.next()) {
//取出第一列的值赋给empNO
emp.setEmpNo(rs.getInt(1));
emp.setEname(rs.getString(2));
emp.setJob(rs.getString(3));
emp.setMgr(rs.getInt(4));
emp.setHireDate(rs.getString(5));
emp.setSal(rs.getDouble(6));
emp.setComm(rs.getDouble(7));
emp.setDeptNo(rs.getInt(8));
emp.setState(1);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBManager.closeConn(conn, ps);
}
return emp;
}
//全表查询--集合
public List<Emp> findAllEmp() {
List<Emp> list = new ArrayList<>();
try {
conn = DBManager.getConnection();
String sql = "select * from emp where state = 1";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
Emp emp = new Emp();//每循环一次new一个新对象,给对象付一次值
emp.setEmpNo(rs.getInt(1));
emp.setEname(rs.getString(2));
emp.setJob(rs.getString(3));
emp.setMgr(rs.getInt(4));
emp.setHireDate(rs.getString(5));
emp.setSal(rs.getDouble(6));
emp.setComm(rs.getDouble(7));
emp.setDeptNo(rs.getInt(8));
emp.setState(1);
list.add(emp);//循环一次在集合中增加一条数据
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBManager.closeConn(conn, ps);
}
return list;
}
}
多表联查
//多表联查
//方法一:
public List<Emp> findAllEmp2(){
List<Emp> list = new ArrayList<>();
try {
conn = DBManager.getConnection();
String sql = "select * from emp e left join Dept d on e.deptNo = d.deptNo where state =1";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()){
Emp emp = new Emp();
emp.setEmpNo(rs.getInt(1));
emp.setEname(rs.getString(2));
emp.setJob(rs.getString(3));
emp.setMgr(rs.getInt(4));
emp.setHireDate(rs.getString(5));
emp.setSal(rs.getDouble(6));
emp.setComm(rs.getDouble(7));
emp.setDeptNo(rs.getInt(8));
emp.setState(1);
emp.setDname(rs.getString(11));
emp.setLoc(rs.getString(12));
list.add(emp);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBManager.closeConn(conn, ps,rs);
}
return list;
}
//方法二:
public List<Emp> findAllEmp3(){
List<Emp> list = new ArrayList<>();
try {
conn = DBManager.getConnection();
String sql = "select * from emp e left join Dept d on e.deptNo = d.deptNo where state =1";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()){
Emp emp = new Emp();
emp.setEmpNo(rs.getInt(1));
emp.setEname(rs.getString(2));
emp.setJob(rs.getString(3));
emp.setMgr(rs.getInt(4));
emp.setHireDate(rs.getString(5));
emp.setSal(rs.getDouble(6));
emp.setComm(rs.getDouble(7));
emp.setDeptNo(rs.getInt(8));
emp.setState(1);
Dept dept = new Dept();
dept.setDeptNo(rs.getInt(10));
dept.setDname(rs.getString(11));
dept.setLoc(rs.getString(12));
emp.setDept(dept);//引入dept表
list.add(emp);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBManager.closeConn(conn, ps,rs);
}
return list;
}
}
App运行代码
public class App {
//删除
private static void a(){
EmpDAO edao = new EmpDAO();
edao.delete(7935);
}
//传入参数
private static void b(){
EmpDAO edao = new EmpDAO();
Emp emp = new Emp();
emp.setEname("王铮亮");
emp.setJob("歌手");
emp.setMgr(7960);
emp.setDeptNo(30);
emp.setSal(36785.0);
emp.setComm(123.4);
edao.save(emp);
}
private static void c(){
EmpDAO edao = new EmpDAO();
Emp emp = new Emp();
emp.setEname("陈na");
emp.setMgr(7943);
emp.setJob("页面设计");
emp.setDeptNo(30);
emp.setComm(123.4);
emp.setSal(4788.8);
emp.setEmpNo(7945);
edao.update(emp);
}
private static void d(){
//查询ID = 7956的员工的信息
EmpDAO edao = new EmpDAO();
Emp emp = edao.findEmpByNo(7956);
System.out.println(emp);
}
private static void e(){
EmpDAO edao = new EmpDAO();
List<Emp> list = edao.findAllEmp();
list.forEach(System.out::println);
}
private static void f1(){
EmpDAO edao = new EmpDAO();
List<Emp> list = edao.findAllEmp2();
list.forEach(System.out::println);
}
private static void f2(){
EmpDAO edao = new EmpDAO();
List<Emp> list = edao.findAllEmp3();
list.forEach(System.out::println);
}
public static void main(String[] args) {
f2();
}
}