当前位置:Gxlcms > 数据库问题 > JDBC

JDBC

时间:2021-07-01 10:21:17 帮助过:16人阅读

问题:实际开发中,不可能用工具或者命令行操作数据库,数据库表中的数据最终要使用Java程序来操作,那么Java中如何操作数据库中的数据呢?

 

Java语言中,有一个专门连接数据库的规范(JDBC),专门负责连接数据库进行数据操作的规范

 

JDBC只是SUN编写的一堆接口(规范的体现),SUN公司自己并没有实现

 

 

问题 为什么SUN只定义一个JDBC规范,而不实现呢?

 

因为市面上的数据库很多,每个数据库内部接口不会向外暴露,而且即便是暴露让SUN去实现,市面上很多数据库全部要SUN来实现不现实

 

实际中哪个数据库需要支持JAVA语言,就需要自己实现JavaJDBC规范,因为实现了JDBC很多接口,那么就会有很多实现类,而很多实现类在java中会使用一个专门的包封装起来,叫做jar(在JDBC中叫做驱动包),各大数据库产商实现JDBC规范以后都会把他们jar包放在官网上以供开发者下载使用

 

1.1. JDBC

JDBC(Java DataBase Connectivity):

是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基

JDBC规范对应的api

 

 

2. 入门案例

2.1. 连接数据库

案例使用JDBC操作MySQL数据库

 

2.2. 创建普通java项目

2.3. 在项目下面新建一个lib目录

 

2.4. MySQL驱动包拷贝到项目中并添加依赖

 

 

 

2.5. 获取数据库连接对象

准备:

1.拷贝MySQL的驱动包到项目中去:mysql-connector-java-5.1.x-bin.jar

2.build path,告速项目去哪里去找字节码文件.

--------------------------------------------------------------------------------

操作JDBC的第一步,获取JDBC的连接对象.:Connection.

 

步骤:

  1.加载注册驱动.

    就是把驱动中的Driver字节码加载到JVM.

   Class.forName("com.mysql.jdbc.Driver");

   为什么这句话就可以加载注册驱动?

   第一步:com.mysql.jdbc.Driver.class这份字节码加载到JVM.

   第二步:当一份字节码被加载进JVM,马上就会执行该字节码中的静态代码块.

    第三步:该静态代码中,就在完成,先创建驱动对象,再注册.

  2.通过DriverManager获取连接对象.

    public static Connection getConnection(String url,String user,String password)

 

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbName","root","admin");

 

jdbc:mysql://localhost:3306/dbName

jdbc:mysql:// :连接MySQL数据库的协议,不同数据库协议不一样

localhost:3306 :数据库软件的主机和端口

dbName : 具体要连接数据库

    若数据库安装在本机,并且端口是默认的3306,则可以简写:

    Connection conn = DriverManager.getConnection("jdbc:mysql:///dbName","root","admin");

 

验证已经获取连接:可以在MySQL控制台,使用命令:show processlist; 查看MySQL运行进程.

 

 

 

public class GetConnectionDemo {

public static void main(String[] args) throws Exception {

 

//1.加载注册驱动 : 把当前类对应的字节码加载到JVM中

Class.forName("com.mysql.jdbc.Driver");

//2.获取数据库连接

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

System.out.println(conn);

 

}

}

 

3. 创建表-DDL操作

在其他操作之间先要把数据库表要创建出来

 

创建一张t_student:

id:

name:

age:

/*

 *

 * 创建表操作

 * SQL : create table t_student (id int primary key auto_increment,name varchar(50),age int)

 */

 

public static void main(String[] args) throws Exception {

String sql = "create table t_student (id int primary key auto_increment,name varchar(50),age int)";

//贾琏欲执事

//1,加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

//2,获取数据库连接

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

//3,创建语句对象(用于执行SQL语句的对象)

Statement st = conn.createStatement();

//4, 执行SQL语句

//int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数

//ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象

st.executeUpdate(sql);

//5,释放资源(先开后关)

st.close();

conn.close();

}

 

4. DML操作-表数据的增删改

//DML : 对表数据的增删改操作

public class DMLDemo {

 

/*

 * 向 t_student表中插入一条数据

 * sql : insert into t_student(name,age) values (‘乔峰‘,30)

 */

@Test

public void testInsert() throws Exception {

String sql = "insert into t_student(name,age) values (‘乔峰‘,30)";

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建语句对象

Statement st = conn.createStatement();

 

// 4.执行SQL语句

// int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数

// ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象

int rows = st.executeUpdate(sql);

System.out.println(rows);

//5.释放资源(先开后关)

st.close();

conn.close();

 

}

/*

 * 删除操作: 删除t_student表中的某一条数据

 * SQL :delete from t_student where id = 2

 */

@Test

public void testDelete() throws Exception {

String sql = "delete from t_student where id = 2";

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建语句对象

Statement st = conn.createStatement();

 

// 4.执行SQL语句

// int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数

// ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象

int rows = st.executeUpdate(sql);

System.out.println(rows);

//5.释放资源(先开后关)

st.close();

conn.close();

}

/*

 * 修改操作 : 修改t_student表中的某一条数据

 * SQL : update t_student set name = ‘虚竹‘,age = 50 where id = 3

 */

@Test

public void testUpdate() throws Exception {

String sql = "update t_student set name = ‘虚竹‘,age = 50 where id = 3";

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建语句对象

Statement st = conn.createStatement();

 

// 4.执行SQL语句

// int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数

// ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象

int rows = st.executeUpdate(sql);

System.out.println(rows);

//5.释放资源(先开后关)

st.close();

conn.close();

}

}

 

5. DQL操作-查询操作

5.1. 查询操作的分析

 

 

 

5.2. 查询具体操作

结果集的列的位置

 

 

  1. 使用 rs.next() 偏移光标,循环指定具体的某一行

 

获取数据的具体方法

 Object

getObject(int columnIndex) 
 columnIndex : 通过结果集的位置(1开始)获取对应的数据

 Object

getObject(String columnLabel) 
columnLabel : 通过结果集的 列名获取对应的数据

 

package cn.sxt.jdbc._01connection;

 

 

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.ResultSet;

import java.sql.Statement;

import java.util.ArrayList;

import java.util.List;

 

import org.junit.Test;

 

//DQL :查询操作

public class D_DQLDemo {

 

/*

 * 多行查询 :查询t_student表中的所有数据

 * SQL : select * from t_student

 */

@Test

public void testList() throws Exception {

String sql = "select * from t_student";

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建语句对象

Statement st = conn.createStatement();

 

// 4.执行SQL语句

// int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数

// ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象

ResultSet rs = st.executeQuery(sql);

 

 

//创建list集合用于封装Student对象

List<Student> stus = new ArrayList<>();

 

while(rs.next()) {

//1.通过结果集的位置获取对应的数

/*Object id = rs.getObject(1);

Object name = rs.getObject(2);

Object age = rs.getObject(3);*/

 

//2.通过结果集的 列名获取对应的数据

/*Object id = rs.getObject("id");

Object name = rs.getObject("name");

Object age = rs.getObject("age");*/

//3.通过数据库数据和Java对应的数据类型获取对应的只

int id = rs.getInt("id");

String name = rs.getString("name");

int age = rs.getInt("age");

//System.out.println(id+","+name+","+age);

 

//将获取的数据封装成对应的Student对象

Student stu = new  Student(id, name, age);

 

//将一个个Student对象添加到list集合中

stus.add(stu);

}

 

for (Student student : stus) {

System.out.println(student);

}

//5.释放资源(先开后关)

rs.close();

st.close();

conn.close();

}

 

 

/*

 * 单行查询: 查询出t_student 指定id的信息

 * SQL : select * from t_student where id = 1;

 */

@Test

public void testGetOne() throws Exception {

String sql = "select * from t_student where id = 2";

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建语句对象

Statement st = conn.createStatement();

 

// 4.执行SQL语句

// int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数

// ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象

ResultSet rs = st.executeQuery(sql);

 

if(rs.next()) {

//1.通过结果集的位置获取对应的数

/*Object id = rs.getObject(1);

Object name = rs.getObject(2);

Object age = rs.getObject(3);*/

 

//2.通过结果集的 列名获取对应的数据

/*Object id = rs.getObject("id");

Object name = rs.getObject("name");

Object age = rs.getObject("age");*/

//3.通过数据库数据和Java对应的数据类型获取对应的只

int id = rs.getInt("id");

String name = rs.getString("name");

int age = rs.getInt("age");

//System.out.println(id+","+name+","+age);

 

//将获取的数据封装成对应的Student对象

Student stu = new  Student(id, name, age);

System.out.println(stu);

}

//5.释放资源(先开后关)

rs.close();

st.close();

conn.close();

}

}

 

 

6. 预编译语句对象PreparedStatment

问题 我们有了Statment对象可以执行SQL,为什么还要使用PreparedStatment

 

优势

  1. SQL语句结构清晰,参数的设置和SQL语句分离
  2. 性能更高
  3. 防止SQL注入

 

Statement: 表示静态SQL语句对象.

PreparedStatement:Statement的子接口,表示预编译SQL语句对象. 通过占位符(?)来拼SQL.  

6.1. 创建PreparedStatement

创建语句对象 Statment

 Statement

createStatement() 
创建一个 Statement 对象来将 SQL 语句发送到数据库。

 

创建预编译语句对象PreparedStatement

 PreparedStatement

prepareStatement(String sql) 
创建预编译语句对象,SQL是带有占位符的SQL模板.

 

 

 

6.2. 执行SQL语句的方法

6.2.1. Statment

在执行SQL语句的时候回带上SQL语句

 ResultSet

executeQuery(String sql) 
          执行给定的 SQL 语句,该语句返回单个 ResultSet 对象。

 int

executeUpdate(String sql) 
          执行给定 SQL 语句,该语句可能为 INSERT、UPDATE 或 DELETE 语句,或者不返回任何内容的 SQL 语句(如 SQL DDL 语句)。

 

6.2.2. PreparedStatement 

在执行SQL语句的方法中不需要设置SQL语句

 ResultSet

executeQuery() 
          在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的 ResultSet 对象。

 int

executeUpdate() 
          在此 PreparedStatement 对象中执行 SQL 语句,该语句必须是一个 SQL 数据操作语言(Data Manipulation Language,DML)语句,比如 INSERT、UPDATE 或 DELETE 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。

 

 

6.3. 设置站位参数的值

void  setXxx(int parameterIndex,Xxx value):用于设置占位符参数,

       parameterIndex:第几个问号. 注意:1开始.

       value:设置的真实值.

Xxx:表示数据类型.String/int/long/Double

 

6.4. 代码

package cn.sxt.jdbc._01connection;

 

import static org.junit.Assert.*;

 

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

 

import org.junit.Test;

 

//DML : 对表数据的增删改操作,使用预编译语句对象

public class E_DMLByPreparedStatmentDemo {

 

/*

 * 向 t_student表中插入一条数据

 * sql : insert into t_student(name,age) values (‘乔峰‘,30)

 */

@Test

public void testInsert() throws Exception {

String sql = "insert into t_student(name,age) values (?,?)";

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建预编译语句对象

PreparedStatement ps = conn.prepareStatement(sql);

//3.1设置占位符参数

ps.setString(1, "东方姑娘");

ps.setInt(2, 18);

 

// 4.执行SQL语句:注意不要带SQL参数

ps.executeUpdate();

//5.释放资源(先开后关)

ps.close();

conn.close();

 

}

/*

 * 删除操作: 删除t_student表中的某一条数据

 * SQL :delete from t_student where id = 2

 */

@Test

public void testDelete() throws Exception {

String sql = "delete from t_student where id = ?";

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建预编译语句对象

PreparedStatement ps = conn.prepareStatement(sql);

//3.1设置占位符对应的参数值

ps.setInt(1, 1);

 

// 4.执行SQL语句

int rows = ps.executeUpdate();

System.out.println(rows);

//5.释放资源(先开后关)

ps.close();

conn.close();

}

/*

 * 修改操作 : 修改t_student表中的某一条数据

 * SQL : update t_student set name = ‘虚竹‘,age = 50 where id = 3

 */

@Test

public void testUpdate() throws Exception {

String sql = "update t_student set name = ?,age = ? where id = ?";

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建预编译语句对象

PreparedStatement ps = conn.prepareStatement(sql);

//3.1设置占位符参数对应的值

ps.setString(1, "西方失败");

ps.setInt(2, 40);

ps.setInt(3, 4);

// 4.执行SQL语句

int rows = ps.executeUpdate();

System.out.println(rows);

//5.释放资源(先开后关)

ps.close();

conn.close();

}

}

 

 

7. DAO设计

实际开发中,JavaWeb开发代码一般分为三层,分层结构是JavaWeb开发中的一种设计思想,这样会让我们开发层次分明,每一层只要完成对应的功能即可,使得项目便于开发和维护

 

1 . Web/表现层 : 主要接受前台浏览器用户的参数,给浏览器响应数据等等

  1. Service/业务成:主要处理业务功能,日志,权限,事物,等等
  2. DAO/持久层 :专门负责和数据库交互,数据处理相关代码

 

 

DAO Data Access Object 数据访问对象

 

 

7.1. DAO思想

 

 

7.2. 使用DAO以后代码的以及包的设计结构

开发中如果使用的分层,编写的包和类名接口名等等都是有固定规则,不能随便瞎写

7.2.1. DAO层接口包命名

 

公司域名倒写+项目名称/模块名称+dao

如 : cn.sxt.crm.dao

7.2.2. DAO层实现类包命名

 

公司域名倒写+项目名称/模块名称+dao+impl

如 : cn.sxt.crm.dao.impl

 

7.2.3. DAO层操作对应表的接口命名

 

对应表的名称 + Dao/DAO

 

如 : StudentDao/DAO , TeacherDao/DAO

 

7.2.4. DAO层操作对应表的实现类命名

 

对应表的名称 + Dao/DAOImpl

 

如 : StudentDaoImpl/DAOImpl , TeacherDaoImpl/DAOImpl

7.2.5. 数据表对应的Javadomain/pojo包命名
POJOPlain Ordinary Java Object)简单的Java对象

 

公司域名倒写+项目名称/模块名称+domain/pojo

如 : cn.sxt.crm.domain

 

7.2.6. 对应的测试包命名

公司域名倒写+项目名称/模块名称+test

如 : cn.sxt.crm.test

7.2.7. 项目的工具类包命名

公司域名倒写+项目名称/模块名称+util/utils

如 : cn.sxt.crm.util/utils

 

 

7.2.8. DAO代码设计结构

 

 

7.2.9. Dao的实现类代码

package cn.sxt.jdbc.dao.impl;

 

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.List;

 

import cn.sxt.jdbc.dao.StudentDao;

import cn.sxt.jdbc.domain.Student;

 

public class StudentDaoImpl implements StudentDao {

 

@Override

public int saveStudent(Student stu) {

String sql = "insert into t_student(name,age) values (?,?)";

 

Connection conn = null;

PreparedStatement ps = null;

try {

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建预编译语句对象

ps = conn.prepareStatement(sql);

//3.1设置占位符参数

ps.setString(1, stu.getName());

ps.setInt(2, stu.getAge());

 

// 4.执行SQL语句:注意不要带SQL参数

return ps.executeUpdate();

 

 

} catch (Exception e) {

e.printStackTrace();

}finally {

//5.释放资源(先开后关)

try {

if(ps !=null) {

ps.close();

}

} catch (SQLException e) {

e.printStackTrace();

}finally {

try {

if(conn !=null) {

conn.close();

}

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

return 0;

}

 

@Override

public int deleteById(int id) {

 

String sql = "delete from t_student where id = ?";

 

Connection conn = null;

PreparedStatement ps = null;

try {

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建预编译语句对象

ps = conn.prepareStatement(sql);

//3.1设置占位符参数

ps.setInt(1, id);

 

// 4.执行SQL语句:注意不要带SQL参数

return ps.executeUpdate();

 

 

} catch (Exception e) {

e.printStackTrace();

}finally {

//5.释放资源(先开后关)

try {

if(ps !=null) {

ps.close();

}

} catch (SQLException e) {

e.printStackTrace();

}finally {

try {

if(conn !=null) {

conn.close();

}

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

return 0;

}

 

@Override

public int updateStudentById(Student stu) {

 

String sql = "update t_student set name = ?,age = ? where id = ?";

 

Connection conn = null;

PreparedStatement ps = null;

try {

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建预编译语句对象

ps = conn.prepareStatement(sql);

//3.1设置占位符参数

ps.setString(1, stu.getName());

ps.setInt(2, stu.getAge());

ps.setInt(3, stu.getId());

// 4.执行SQL语句:注意不要带SQL参数

return ps.executeUpdate();

 

 

} catch (Exception e) {

e.printStackTrace();

}finally {

//5.释放资源(先开后关)

try {

if(ps !=null) {

ps.close();

}

} catch (SQLException e) {

e.printStackTrace();

}finally {

try {

if(conn !=null) {

conn.close();

}

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

return 0;

}

 

@Override

public Student selectById(int id) {

String sql = "select * from t_student where id = ?";

 

Connection conn = null;

PreparedStatement ps = null;

ResultSet rs = null;

 

try {

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建语句对象

ps = conn.prepareStatement(sql);

//3.1设置占位符参数对应的值

ps.setInt(1, id);

 

// 4.执行SQL语句

rs = ps.executeQuery();

if(rs.next()) {

//通过数据库数据和Java对应的数据类型获取对应的只

String name = rs.getString("name");

int age = rs.getInt("age");

//System.out.println(id+","+name+","+age);

 

//将获取的数据封装成对应的Student对象

Student stu = new  Student(id, name, age);

 

return stu;

}

 

} catch (Exception e) {

// TODO: handle exception

}finally {

try {

if(rs !=null) {

rs.close();

}

} catch (SQLException e) {

e.printStackTrace();

}finally {

try {

if(ps !=null) {

ps.close();

}

} catch (SQLException e) {

e.printStackTrace();

}finally {

try {

if(conn !=null) {

conn.close();

}

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

 

return null;

}

 

@Override

public List<Student> selectList() {

String sql = "select * from t_student";

//创建list集合用于封装Student对象

List<Student> stus = new ArrayList<>();

 

Connection conn = null;

PreparedStatement ps = null;

ResultSet rs = null;

 

try {

 

// 1.加载注册驱动

Class.forName("com.mysql.jdbc.Driver");

 

// 2.获取数据库连接对象

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.创建语句对象

ps = conn.prepareStatement(sql);

 

// 4.执行SQL语句

rs = ps.executeQuery();

while(rs.next()) {

//通过数据库数据和Java对应的数据类型获取对应的只

int id = rs.getInt("id");

String name = rs.getString("name");

int age = rs.getInt("age");

//System.out.println(id+","+name+","+age);

 

//将获取的数据封装成对应的Student对象

Student stu = new  Student(id, name, age);

//将一个个Student对象添加到list集合中

stus.add(stu);

}

 

} catch (Exception e) {

// TODO: handle exception

}finally {

try {

if(rs !=null) {

rs.close();

}

} catch (SQLException e) {

e.printStackTrace();

}finally {

try {

if(ps !=null) {

ps.close();

}

} catch (SQLException e) {

e.printStackTrace();

}finally {

try {

if(conn !=null) {

conn.close();

}

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

 

return stus;

}

 

}

 

 

7.3. 代码初步重构

上述的DAO方法中的代码,存在的问题:

 

问题1:每个DAO方法中都会写:驱动名称/url/账号/密码,不利于维护.

    解决方案: 声明为成员变量即可.(在被类中任何地方都可以访问)

 

问题2:问题1的解决方案有问题.

    每个DAO实现类里都有一模一样的4行代码,不利于维护(考虑有100个DAO实现类,就得重复99次).

    解决方案: 把驱动名称/url/账号/密码这四行代码,专门抽取到一个JDBC的工具类中.---->JdbcUtil.

问题3:其实DAO方法,每次操作都只想需要Connection对象即可,而不关心是如何创建的.

    解决方案:把创建Connection的代码,抽取到JdbcUtil中,并提供方法getConn用于向调用者返回Connection对象即可.

问题4:每次调用者调用getConn方法的时候,都会创建一个Connection对象.

      但是,每次都会加载注册驱动一次.--->没必要的.

      解决方案:把加载注册驱动的代码放在静态代码块中--->只会在所在类被加载进JVM的时候,执行一次.

问题5:每个DAO方法都要关闭资源.(鸡肋代码).

      解决方案:把关闭资源的代码,抽取到JdbcUtil中.

      public static void close(Connection conn, Statement st, ResultSet rs) {}

      调用者:

        DML:  JdbcUtil.close(conn,st,null);

        DQL:  JdbcUtil.close(conn,st,rs);

问题6 :连接数据库的账号密码写死在JdbcUtil工具类中了,不利于维护

     抽取 db.properties 配置文件,将数据库对应的账号密码写到配置文件中,然后使用程序读取配置文件内容即可

 

 

7.3.1. JdbcUtil工具类

package cn.sxt.jdbc.util;

 

import java.io.InputStream;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.Properties;

 

 

public class JdbcUtil {

 

// alt+shif+a 多行修改,修改以后还原 alt+shif+a

 

/*private static String driverClassName = "com.mysql.jdbc.Driver";

private static String url = "jdbc:mysql://localhost:3306/jdbcdemo";

private static String username = "root";

private static String password = "root";*/

 

private static Properties p = new Properties();

 

static {

try {

//1.获取类加载器

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

//2,使用类加载器获取项目 类路径下面的文件

InputStream inputStream = classLoader.getResourceAsStream("db.properties");

 

//3.使用Priperties加载配置文件对应的输入流

p.load(inputStream);

 

Class.forName(p.getProperty("driverClassName"));

} catch (Exception e) {

e.printStackTrace();

}

}

 

public static Connection getConnection() {

try {

 

return DriverManager.getConnection(p.getProperty("url"), p.getProperty("username"), p.getProperty("password"));

} catch (Exception e) {

e.printStackTrace();

throw new RuntimeException("亲,连接数据库失败", e);

}

}

 

public static void close(Connection conn,PreparedStatement ps,ResultSet rs) {

try {

if(rs !=null) {

rs.close();

}

} catch (SQLException e) {

e.printStackTrace();

}finally {

try {

if(ps !=null) {

ps.close();

}

} catch (SQLException e) {

e.printStackTrace();

}finally {

try {

if(conn !=null) {

conn.close();

}

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

}

 

7.3.2. 使用工具类以后的DAO实现类效果

package cn.sxt.jdbc.dao.impl;

 

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.List;

 

import cn.sxt.jdbc.dao.StudentDao;

import cn.sxt.jdbc.domain.Student;

import cn.sxt.jdbc.util.JdbcUtil;

 

public class StudentDaoImpl implements StudentDao {

 

 

 

@Override

public int saveStudent(Student stu) {

String sql = "insert into t_student(name,age) values (?,?)";

 

Connection conn = null;

PreparedStatement ps = null;

try {

conn = JdbcUtil.getConnection();

 

// 3.创建预编译语句对象

ps = conn.prepareStatement(sql);

//3.1设置占位符参数

ps.setString(1, stu.getName());

ps.setInt(2, stu.getAge());

 

// 4.执行SQL语句:注意不要带SQL参数

return ps.executeUpdate();

 

} catch (Exception e) {

e.printStackTrace();

}finally {

JdbcUtil.close(conn, ps, null);

}

return 0;

}

 

@Override

public int deleteById(int id) {

 

String sql = "delete from t_student where id = ?";

 

Connection conn = null;

PreparedStatement ps = null;

try {

 

conn = JdbcUtil.getConnection();

// 3.创建预编译语句对象

ps = conn.prepareStatement(sql);

//3.1设置占位符参数

ps.setInt(1, id);

 

// 4.执行SQL语句:注意不要带SQL参数

return ps.executeUpdate();

 

 

} catch (Exception e) {

e.printStackTrace();

}finally {

JdbcUtil.close(conn, ps, null);

}

return 0;

}

 

@Override

public int updateStudentById(Student stu) {

 

String sql = "update t_student set name = ?,age = ? where id = ?";

 

Connection conn = null;

PreparedStatement ps = null;

try {

 

conn = JdbcUtil.getConnection();

// 3.创建预编译语句对象

ps = conn.prepareStatement(sql);

//3.1设置占位符参数

ps.setString(1, stu.getName());

ps.setInt(2, stu.getAge());

ps.setInt(3, stu.getId());

// 4.执行SQL语句:注意不要带SQL参数

return ps.executeUpdate();

 

 

} catch (Exception e) {

e.printStackTrace();

}finally {

JdbcUtil.close(conn, ps, null);

}

return 0;

}

 

@Override

public Student selectById(int id) {

String sql = "select * from t_student where id = ?";

 

Connection conn = null;

PreparedStatement ps = null;

ResultSet rs = null;

 

try {

conn = JdbcUtil.getConnection();

// 3.创建语句对象

ps = conn.prepareStatement(sql);

//3.1设置占位符参数对应的值

ps.setInt(1, id);

 

// 4.执行SQL语句

rs = ps.executeQuery();

if(rs.next()) {

//通过数据库数据和Java对应的数据类型获取对应的只

String name = rs.getString("name");

int age = rs.getInt("age");

//System.o

人气教程排行