为什么进行JDBC封装2-1
1、将相似功能的代码抽取封装成方法,减少代码冗余
2、因为不同的数据库会有不同的实现,对数据库的操作一般抽取成接口,在以后的开发中可以降低耦合
- 隔离业务逻辑代码和数据访问代码
- 隔离不同数据库的实现
实现JDBC封装
- 将所有增删改查操作抽取成接口
- 定义实体类传输数据
- 将通用的操作(打开、关闭连接等)封装到工具类
- 数据库工具类BaseDao:增、删、改、查的通用方法
public class BaseDao {
public Connection getConn() throws Exception {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://192.168.83.35:3306/MySchool";
//驱动管理器来获取连接
Connection conn= DriverManager.getConnection(url,"root","ok");
return conn;
}
public void showTables() throws Exception {
//获取连接
Connection conn=getConn();
//先获取Statement对象
Statement stmt=conn.createStatement();
String sql="show tables";
ResultSet rs = stmt.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getString("Tables_in_MySchool"));
}
}
public ResultSet query(String sql) throws Exception{
Connection conn=getConn();
Statement stmt=conn.createStatement();
String sql1=sql;
ResultSet rs = stmt.executeQuery(sql1);
return rs;
}
public int update(String sql)throws Exception{
Connection conn=getConn();
Statement stmt=conn.createStatement();
int i = stmt.executeUpdate(sql);
return i;
}
}
package demo;
import entiry.Student;
import org.junit.Test;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import static org.junit.Assert.*;
public class BaseDaoTest {
@Test
public void getConn() throws Exception {
BaseDao dao=new BaseDao();
Connection conn=dao.getConn();
System.out.println(conn);
}
@Test
public void showTables() throws Exception {
BaseDao dao=new BaseDao();
dao.showTables();
}
@Test
public void query() throws Exception {
BaseDao dao=new BaseDao();
String sql="select * from student";
ResultSet rs=dao.query(sql);
ArrayList<Student> stulist=new ArrayList<>();
while (rs.next()){
Student s=new Student();
s.setStudentNo(rs.getInt("StudentNo"));
s.setStudentName(rs.getString("StudentName"));
stulist.add(s);
}
for (Student student : stulist) {
System.out.println(student);
}
}
@Test
public void update() throws Exception {
BaseDao dao=new BaseDao();
String sql="insert into student(StudentNo,StudentName) "+
"values(1011,'一灯'),(1065,'因故')";
int num=dao.update(sql);
System.out.println(num > 0 ? "插入成功" : "插入失败");
}
//使用jdbc创建一个库,切换到这个库,创建一个表
@Test
public void testDo() throws Exception{
BaseDao dao=new BaseDao();
Connection conn=dao.getConn();
Statement stmt=conn.createStatement();
String createDabase="create database if not exists userControl";
boolean isSuccess = stmt.execute(createDabase);
System.out.println(isSuccess);
String changeDatabase="use userControl";
stmt.execute(changeDatabase);
String createTable="create table user_info(" +
"uid int(11) auto_increment primary key," +
"uname varchar(30)," +
"password varchar(30))";
stmt.execute(createTable);
}
}
什么是DAO
- Data Access Object(数据存取对象)
- 位于业务逻辑和持久化数据之间
- 实现对持久化数据的访问
DAO模式的组成
DAO模式的组成部分
- DAO接口
- DAO实现类
- 实体类
- 数据库连接和关闭工具类
优势
- 隔离了数据访问代码和业务逻辑代码
- 隔离了不同数据库实现
配置数据库访问参数
弊端
数据库发生改变时,要重新修改代码,重新编译和部署
解决
将数据库信息写在配置文件当中,让程序通过读取配置文件来获得这些信息
属性文件
- 后缀为.properties
- 数据格式为“键=值”
- 使用“#”来注释
package demo;
import until.Prop;
import java.sql.*;
/**
* @Author lichangxin
* @date 2020-08-21
* @Des
*/
public class PstDao {
private static String driver= Prop.getP("driver");
private static String url=Prop.getP("url");
private static String user=Prop.getP("user");
private static String pwd=Prop.getP("pwd");
public static Connection getConn(){
try {
Class.forName(driver);
return DriverManager.getConnection(url,user,pwd);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void close(Connection conn, PreparedStatement pst, ResultSet rs){
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (pst!=null){
try {
pst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static ResultSet query(String sql,Object ...params ){
Connection conn = getConn();
PreparedStatement pst=null;
ResultSet rs=null;
try {
pst=conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pst.setObject(i+1,params[i]);
}
rs=pst.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}finally {
// close(conn,pst,null);
}
return rs;
}
public static int update(String sql,Object...params){
Connection conn=getConn();
PreparedStatement pst=null;
try {
pst=getConn().prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pst.setObject(i+1,params[i]);
}
return pst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {if (pst!=null) {
pst.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn!=null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return -1;
}
}
package demo;
import org.junit.Test;
import java.sql.ResultSet;
import java.sql.SQLException;
import static org.junit.Assert.*;
public class PstDaoTest {
@Test
public void query() throws SQLException {
String sql="SELECT SubjectName,score FROM `subject` s " +
"JOIN result r ON s.SubjectNo=r.sub_no WHERE score>? AND SubjectName IN(?,?)";
ResultSet rs=PstDao.query(sql,60,"高等数学-1","高等数学-2");
while (rs.next()){
System.out.print(rs.getString("SubjectName")+"----");
System.out.println(rs.getInt("score"));
}
rs.close();
}
@Test
public void update(){
String sql="update account set cash=cash+? where name=?";
int num=PstDao.update(sql,10000,"icbc");
System.out.println(num > 0 ? "更新成功" : "更新失败");
}
}
package until;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
/**
* @Author lichangxin
* @date 2020-08-21
* @Des
*/
public class Prop {
private static Properties p=new Properties();
public static String getP(String param){
try {
p.load(new FileInputStream("resources/db.properties"));
} catch (IOException e) {
e.printStackTrace();
}
return p.getProperty(param);
}
}
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.83.35:3306/shop
user=root
pwd=ok
为何需要单例模式
- BaseDao:操作数据库的基类
- 每个线程对系统操作都需new一个BaseDao实例
- 初始化时的I/O操作消耗系统资源,影响系统性能
系统运行期间,有且仅有一个实例
一个类只有一个实例——最基本的要求
只提供私有构造器
它必须自行创建这个实例
定义了静态的该类私有对象
它必须自行向整个系统
提供这个实例提供一个静态的公有方法,返回创建或者获取本身的静态私有对象
懒汉模式
在类加载时不创建实例,采用延迟加载的方式,在运行调用时创建实例
特点
- 线程不安全
- 延迟加载(lazy loading)
如何解决线程安全问题?
同步(synchronized)
饿汉模式
在类加载的时候,就完成初始化
特点
- 线程安全
- 不具备延迟加载特性
单例模式 | 懒汉模式 | 饿汉模式 |
---|---|---|
概念 | 在类加载时不创建实例,采用延迟加载的方式,在运行调用时创建实例 | 在类加载的时候,就完成初始化 |
特点 | 类加载速度快,但是运行时获取对象的速度较慢。——“时间换空间” | 类加载较慢,但获取对象速度快。——“空间换时间” |
延迟加载(lazy loa ding) | 具备 | 不具备 |
线程安全 | 线程不安全 | 线程安全 |