0%

JDBC高阶

  • DAO模式
  • 员工管理系统开发
  • 封装BaseDao
  • 连接池
  • log4j日志框架
  • 三大范式
  • 数据库之间的三大关系

DAO模式

介绍

DAO(Data Access Object)是一个数据访问接口,数据访问:顾名思义就是与数据库打交道。夹在业务逻辑与数据库资源中间。

在核心J2EE模式中是这样介绍DAO模式的:为了建立一个健壮的J2EE应用,应该将所有对数据源的访问操作抽象封装在一个公共API中。用程序设计的语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口在逻辑上对应这个特定的数据存储.

简单来说,就是定义一个接口,规定一些增删改查的方法,然后交给实现类去实现, 它介于数据库和业务逻辑代码之间,这样当我们需要操作数据库是,根据接口定义的API去操作数据库就可以了,每个方法都是一个原子性的操作,例如:增加、修改、删除等

Dao模式要求项目必须具备这样几个结构:

  1. 实体类:和数据库表格一 一对应的类,单独放入一个包中,包名往往是 pojo/entity/bean,要操作的每个表格都应该有对应的实体类
1
2
3
emp > class Emp  
dept > class Dept
account > class Account
  1. DAO 层:定义了对数据要执行那些操作的接口和实现类,包名往往是 dao/mapper,要操作的每个表格都应该有对应的接口和实现类
1
2
emp > interface EmpDao >EmpDaoImpl
dept > interface DeptDao> DeptDaoImpl
  1. Mybatis/Spring JDBCTemplate 中,对DAO层代码进行了封装,代码编写方式会有其他变化
项目的搭建
  1. 创建项目(Java模块)

  2. 添加jar包

  3. 创建包(pojo、dao)

  4. 创建实体类Emp(有多少表创多少类)

  5. 创建后台的接口EmpDao和实现类EmpDaoImpl

项目结构图

项目结构图

实体类代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package com.excepenxi.pojo;

import java.io.Serializable;
import java.util.Date;

// 1.创建实体类
public class Emp implements Serializable {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
// date导入类 建议选择java.util对象,是java.sql的父类
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;

// 5.方便测试 toString()
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", mgr=" + mgr +
", hiredate=" + hiredate +
", sal=" + sal +
", comm=" + comm +
", deptno=" + deptno +
'}';
}

// 4.包含全部参数构造方法 Constructor ==> OK
public Emp(Integer empno, String ename, String job, Integer mgr, Date hiredate, Double sal, Double comm, Integer deptno) {
this.empno = empno;
this.ename = ename;
this.job = job;
this.mgr = mgr;
this.hiredate = hiredate;
this.sal = sal;
this.comm = comm;
this.deptno = deptno;
}

// 3.无参构造方法 Constructor ==> Select None
public Emp(){
}

// 2.所有的属性都要有get和set方法 Getter Setter
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Integer getMgr() {
return mgr;
}
public void setMgr(Integer mgr) {
this.mgr = mgr;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
public Double getComm() {
return comm;
}
public void setComm(Double comm) {
this.comm = comm;
}
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.excepenxi.pojo;

import java.io.Serializable;

// 1.创建实体类
public class Dept implements Serializable {
private Integer deptno;
private String dname;
private String loc;

// 5.方便测试 toString()
@Override
public String toString() {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
", loc='" + loc + '\'' +
'}';
}

// 4.包含全部参数构造方法 Constructor ==> OK
public Dept(Integer deptno, String dname, String loc) {
this.deptno = deptno;
this.dname = dname;
this.loc = loc;
}

// 3.无参构造方法 Constructor ==> Select None
public Dept() {
}

// 2.所有的属性都要有get和set方法 Getter Setter
public Integer getDeptno() {
return deptno;
}

public void setDeptno(Integer deptno) {
this.deptno = deptno;
}

public String getDname() {
return dname;
}

public void setDname(String dname) {
this.dname = dname;
}

public String getLoc() {
return loc;
}

public void setLoc(String loc) {
this.loc = loc;
}
}
DAO接口代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.excepenxi.dao;

import com.excepenxi.pojo.Emp;

public interface EmpDao {
/**
* 向数据库Emp表中增加一条数据的方法
* @param emp 要增加的数据封装成的Emp类的对象
* @return 增加成功返回大于0 的整数,增加失败返回0
*/
int addEmp(Emp emp);
/**
* 根据员工编号删除员工信息的方法
* @param empno 要删除的员工编号
* @return 删除成功返回大于0的整数,失败返回0
*/
int deleteByEmpno(int empno);
}
1
2
3
4
package com.excepenxi.dao;

public interface DeptDao {
}
DAO实现类代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package com.excepenxi.dao.impl;

import com.excepenxi.dao.EmpDao;
import com.excepenxi.pojo.Emp;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class EmpDaoImpl implements EmpDao {
private static String driver ="com.mysql.cj.jdbc.Driver";
private static String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
private static String user="root";
private static String password="root";

@Override
public int addEmp(Emp emp) {
// 向 Emp表中增加一条数据
Connection connection = null;
PreparedStatement preparedStatement=null;
int rows=0;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url, user,password);
String sql="insert into emp values(DEFAULT ,?,?,?,?,?,?,?)";
preparedStatement = connection.prepareStatement(sql);//这里已经传入SQL语句
//设置参数 setObject自动判断数据类型
preparedStatement.setObject(1,emp.getEname());
preparedStatement.setObject(2,emp.getJob() );
preparedStatement.setObject(3,emp.getMgr());
preparedStatement.setObject(4,emp.getHiredate());
preparedStatement.setObject(5,emp.getSal());
preparedStatement.setObject(6,emp.getComm());
preparedStatement.setObject(7,emp.getDeptno());
//执行CURD
rows =preparedStatement.executeUpdate();// 这里不需要再传入SQL语句
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != connection){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return rows;
}

@Override
public int deleteByEmpno(int empno) {
// 向 Emp表中删除一条数据
Connection connection = null;
PreparedStatement preparedStatement=null;
int rows=0;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url, user,password);
String sql="delete from emp where empno =?";
preparedStatement = connection.prepareStatement(sql);//这里已经传入SQL语句
//设置参数
preparedStatement.setObject(1,empno);
//执行CURD
rows =preparedStatement.executeUpdate();// 这里不需要再传入SQL语句
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != connection){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return rows;
}
}
1
2
3
4
5
6
package com.excepenxi.dao.impl;

import com.excepenxi.dao.DeptDao;

public class DeptDaolmpl implements DeptDao {
}
运行测试

image-20220530001533179

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.excepenxi.test1;

import com.excepenxi.dao.EmpDao;
import com.excepenxi.dao.impl.EmpDaoImpl;
import com.excepenxi.pojo.Emp;

import java.util.Date;

public class Test1 {
public static void main(String[] args) {
EmpDao empDao = new EmpDaoImpl();

// 增加数据
Emp emp = new Emp(null,"JHON","MANAGER",7839,new Date(),3000.12,1000.31,30);
int rows = empDao.addEmp(emp);
System.out.println(rows);

// 删除数据
/*
int rows = empDao.deleteByEmpno(10002); // 员工编号对应10002
System.out.println(rows);
*/
}
}

员工管理系统开发

结构图

DAO接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.excepenxi.dao;

import com.excepenxi.pojo.Emp;
import java.util.List;
public interface EmpDao {
/**
* 向数据库Emp表中增加一条数据的方法
* @param emp 要增加的数据封装成的Emp类的对象
* @return 增加成功返回大于0 的整数,增加失败返回0
*/
int addEmp(Emp emp);
/**
* 根据员工编号删除员工信息的方法
* @param empno 要删除的员工编号
* @return 删除成功返回大于0的整数,失败返回0
*/
int deleteByEmpno(int empno);

/**
* 查看数据库表格中所有的员工信息
* @return 所有员工信息封装的一个List<Emp>集合
*/
List<Emp> findAll();
/**
* 根据员工编号修改员工其他所有字段的方法
* @param emp 员工编号和其他7个字段封装的一个Emp类对象
* @return 修改成功返回大于0的整数,失败返回0
*/
int updateEmp(Emp emp);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.excepenxi.dao;

import com.excepenxi.pojo.Dept;
import java.util.List;

public interface DeptDao {
/**
* 查询全部门的方法
* @return Dept对象封装的List集合
*/
List<Dept> findAll();

int addDept(Dept dept);
}
DAO实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package com.excepenxi.dao.impl;

import com.excepenxi.dao.EmpDao;
import com.excepenxi.pojo.Emp;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class EmpDaoImpl implements EmpDao {
private static String driver ="com.mysql.cj.jdbc.Driver";
private static String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
private static String user="root";
private static String password="root";

@Override
public int addEmp(Emp emp) {
// 向 Emp表中增加一条数据
Connection connection = null;
PreparedStatement preparedStatement=null;
int rows=0;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url, user,password);
String sql="insert into emp values(DEFAULT ,?,?,?,?,?,?,?)";
preparedStatement = connection.prepareStatement(sql);//这里已经传入SQL语句
//设置参数 setObject自动判断数据类型
preparedStatement.setObject(1,emp.getEname());
preparedStatement.setObject(2,emp.getJob() );
preparedStatement.setObject(3,emp.getMgr());
preparedStatement.setObject(4,emp.getHiredate());
preparedStatement.setObject(5,emp.getSal());
preparedStatement.setObject(6,emp.getComm());
preparedStatement.setObject(7,emp.getDeptno());
//执行CURD
rows =preparedStatement.executeUpdate();// 这里不需要再传入SQL语句
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != connection){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return rows;
}

@Override
public int deleteByEmpno(int empno) {
// 向 Emp表中删除一条数据
Connection connection = null;
PreparedStatement preparedStatement=null;
int rows=0;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url, user,password);
String sql="delete from emp where empno =?";
preparedStatement = connection.prepareStatement(sql);//这里已经传入SQL语句
//设置参数
preparedStatement.setObject(1,empno);
//执行CURD
rows =preparedStatement.executeUpdate();// 这里不需要再传入SQL语句
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != connection){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return rows;
}

@Override
public List<Emp> findAll() {
// 查询名字中包含字母A的员工信息
Connection connection = null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
List<Emp> list =null;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url, user,password);
String sql="select * from emp";
preparedStatement = connection.prepareStatement(sql);//这里已经传入SQL语句
//执行CURD
resultSet = preparedStatement.executeQuery();// 这里不需要再传入SQL语句
list=new ArrayList<Emp>() ;
while(resultSet.next()){
int empno = resultSet.getInt("empno");
String ename = resultSet.getString("ename");
String job = resultSet.getString("job");
int mgr = resultSet.getInt("mgr");
Date hiredate = resultSet.getDate("hiredate");
double sal= resultSet.getDouble("sal");
double comm= resultSet.getDouble("comm");
int deptno= resultSet.getInt("deptno");
Emp emp =new Emp(empno, ename, job, mgr, hiredate, sal, comm, deptno);
list.add(emp);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != resultSet){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != connection){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return list;
}

@Override
public int updateEmp(Emp emp) {
// 向 Emp表中增加一条数据
Connection connection = null;
PreparedStatement preparedStatement=null;
int rows=0;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url, user,password);
String sql="update emp set ename =? ,job=?, mgr =?,hiredate =?,sal=?,comm=?,deptno=? where empno =?";
preparedStatement = connection.prepareStatement(sql);//这里已经传入SQL语句
//设置参数
preparedStatement.setObject(1,emp.getEname());
preparedStatement.setObject(2,emp.getJob() );
preparedStatement.setObject(3,emp.getMgr());
preparedStatement.setObject(4,emp.getHiredate());
preparedStatement.setObject(5,emp.getSal());
preparedStatement.setObject(6,emp.getComm());
preparedStatement.setObject(7,emp.getDeptno());
preparedStatement.setObject(8,emp.getEmpno());
//执行CURD
rows =preparedStatement.executeUpdate();// 这里不需要再传入SQL语句
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != connection){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return rows;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package com.excepenxi.dao.impl;

import com.excepenxi.dao.DeptDao;
import com.excepenxi.pojo.Dept;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class DeptDaolmpl implements DeptDao {
private static String driver ="com.mysql.cj.jdbc.Driver";
private static String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
private static String user="root";
private static String password="root";

@Override
public List<Dept> findAll() {
// 查询名字中包含字母A的员工信息
Connection connection = null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
List<Dept> list =null;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url, user,password);
String sql="select * from dept";
preparedStatement = connection.prepareStatement(sql);//这里已经传入SQL语句
//执行CURD
resultSet = preparedStatement.executeQuery();// 这里不需要再传入SQL语句
list=new ArrayList<Dept>() ;
while(resultSet.next()){
int deptno = resultSet.getInt("deptno");
String dname = resultSet.getString("dname");
String loc = resultSet.getString("loc");
Dept dept =new Dept(deptno,dname,loc);
list.add(dept);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != resultSet){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != connection){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return list;
}

@Override
public int addDept(Dept dept) {
// 向 Emp表中增加一条数据
Connection connection = null;
PreparedStatement preparedStatement=null;
int rows=0;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url, user,password);
String sql="insert into dept values(?,?,?)";
preparedStatement = connection.prepareStatement(sql);//这里已经传入SQL语句
//设置参数
preparedStatement.setObject(1,dept.getDeptno());
preparedStatement.setObject(2,dept.getDname());
preparedStatement.setObject(3,dept.getLoc() );
//执行CURD
rows =preparedStatement.executeUpdate();// 这里不需要再传入SQL语句
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != connection){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return rows;
}
}
EmpManageSystem类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package com.excepenxi.view;

import com.excepenxi.dao.DeptDao;
import com.excepenxi.dao.EmpDao;
import com.excepenxi.dao.impl.DeptDaolmpl;
import com.excepenxi.dao.impl.EmpDaoImpl;
import com.excepenxi.pojo.Dept;
import com.excepenxi.pojo.Emp;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Scanner;

public class EmpManageSystem {
private static Scanner sc =new Scanner(System.in);
private static EmpDao empDao =new EmpDaoImpl();
private static DeptDao deptDao =new DeptDaolmpl();
private static SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd");;

public static void main(String[] args) {
while(true){
showMenu();
System.out.print("请录入选项:");
int option =sc.nextInt();
switch (option){
case 1:
case1();
break;
case 2:
case2();
break;
case 3:
case3();
break;
case 4:
case4();
break;
case 5:
case5();
break;
case 6:
case6();
break;
case 7:
sc.close();
System.exit(0);
break;
default:
System.out.println("请正确输入选项!!!");
}
}
}

private static void case1(){
List<Emp> emps = empDao.findAll();
emps.forEach(System.out::println);
}
private static void case2(){
List<Dept> depts = deptDao.findAll();
depts.forEach(System.out::println);
}
private static void case3(){
System.out.print("请输入要删除的员工编号:");
int empno=sc.nextInt();
empDao.deleteByEmpno(empno);
}
private static void case4(){
System.out.print("请输入员工编号:");
int empno =sc.nextInt();
System.out.print("请输入员工姓名:");
String ename =sc.next();
System.out.print("请输入员工职位:");
String job =sc.next();
System.out.print("请输入员工上级:");
int mgr =sc.nextInt();
System.out.print("请输入员工入职日期,格式为yyyy-MM-dd:");
Date hiredate =null;
try {
hiredate = simpleDateFormat.parse(sc.next());
} catch (ParseException e) {
e.printStackTrace();
}
System.out.print("请输入员工工资:");
double sal =sc.nextDouble();
System.out.print("请输入员工补助:");
double comm=sc.nextDouble();
System.out.print("请输入员工部门号:");
int deptno =sc.nextInt();
Emp emp=new Emp(empno, ename, job, mgr, hiredate, sal, comm,deptno);
empDao.updateEmp(emp);
}
private static void case5(){
System.out.print("请输入员工姓名:");
String ename =sc.next();
System.out.print("请输入员工职位:");
String job =sc.next();
System.out.print("请输入员工上级:");
int mgr =sc.nextInt();
System.out.print("请输入员工入职日期,格式为yyyy-MM-dd:");
Date hiredate =null;
try {
hiredate = simpleDateFormat.parse(sc.next());
} catch (ParseException e) {
e.printStackTrace();
}
System.out.print("请输入员工工资:");
double sal =sc.nextDouble();
System.out.print("请输入员工补助:");
double comm=sc.nextDouble();
System.out.print("请输入员工部门号:");
int deptno =sc.nextInt();
Emp emp=new Emp(null, ename, job, mgr, hiredate, sal, comm,deptno);
empDao.addEmp(emp);
}
private static void case6(){
System.out.print("请录入部门号:");
int deptno =sc.nextInt();
System.out.print("请录入部门名称:");
String dname =sc.next();
System.out.print("请录入部门位置:");
String loc =sc.next();
Dept dept =new Dept(deptno,dname,loc);
deptDao.addDept(dept);
}

// 显示菜单
public static void showMenu(){
System.out.println("************************************");
System.out.println("* 1 查看所有员工信息");
System.out.println("* 2 查看所有部门信息");
System.out.println("* 3 根据工号删除员工信息");
System.out.println("* 4 根据工号修改员工信息");
System.out.println("* 5 增加员工信息");
System.out.println("* 6 增加部门信息");
System.out.println("* 7 退出");
System.out.println("************************************");
}
}
测试结果

测试
测试

封装BaseDao

目的:处理大量的重复代码

整合

修改

BaseDAO代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package com.excepenxi.dao;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public abstract class BaseDao {
private static String driver ="com.mysql.cj.jdbc.Driver";
private static String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
private static String user="root";
private static String password="root";

// 增删改
public int baseUpdate(String sql,Object ... args){
Connection connection = null;
PreparedStatement preparedStatement=null;
int rows=0;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url, user,password);

preparedStatement = connection.prepareStatement(sql);
//设置参数 setObject自动判断数据类型
for (int i = 0; i <args.length ; i++) {
preparedStatement.setObject(i+1, args[i]);
}
//执行CURD
rows =preparedStatement.executeUpdate();// 这里不需要再传入SQL语句
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != connection){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return rows;
}

// 查
public List baseQuery(Class clazz, String sql, Object ... args) {
// 查询名字中包含字母A的员工信息
Connection connection = null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
List list =null;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url, user,password);
preparedStatement = connection.prepareStatement(sql);//这里已经传入SQL语句
//设置参数
for (int i = 0; i <args.length ; i++) {
preparedStatement.setObject(i+1, args[i]);
}
//执行CURD
resultSet = preparedStatement.executeQuery();// 这里不需要再传入SQL语句
list=new ArrayList() ;
// 根据字节码获取所有 的属性
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);// 设置属性可以 访问
}
while(resultSet.next()){
// 通过反射创建对象
Object obj = clazz.newInstance();//默认在通过反射调用对象的空参构造方法
for (Field field : fields) {// 临时用Field设置属性
String fieldName = field.getName();// empno ename job .... ...
Object data = resultSet.getObject(fieldName);
field.set(obj,data);
}
list.add(obj);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != resultSet){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != connection){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return list;
}
}
实现类代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.excepenxi.dao.impl;

import com.excepenxi.dao.BaseDao;
import com.excepenxi.dao.EmpDao;
import com.excepenxi.pojo.Emp;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class EmpDaoImpl extends BaseDao implements EmpDao {

@Override
public int addEmp(Emp emp) {
String sql="insert into emp values(DEFAULT ,?,?,?,?,?,?,?)";
return baseUpdate(sql,emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno());
}

@Override
public int deleteByEmpno(int empno) {
String sql="delete from emp where empno =?";
return baseUpdate(sql,empno);
}

@Override
public List<Emp> findAll() {
String sql="select * from emp";
return baseQuery(Emp.class,sql);
}

@Override
public int updateEmp(Emp emp) {
String sql="update emp set ename =? ,job=?, mgr =?,hiredate =?,sal=?,comm=?,deptno=? where empno =?";
return baseUpdate(sql,emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno(),emp.getEmpno());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.excepenxi.dao.impl;

import com.excepenxi.dao.BaseDao;
import com.excepenxi.dao.DeptDao;
import com.excepenxi.pojo.Dept;
import com.excepenxi.pojo.Emp;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

// extends BaseDao 继承BaseDao
public class DeptDaolmpl extends BaseDao implements DeptDao {

@Override
public List<Dept> findAll() {
String sql="select * from dept";
return baseQuery(Dept.class,sql);
}

@Override
public int addDept(Dept dept) {
String sql="insert into dept values(?,?,?)";
return baseUpdate(sql,dept.getDeptno(),dept.getDname(),dept.getLoc());
}
}
运行测试

测试结果

连接池(性能优化)

连接池介绍

传统连接方式

首先调用Class.forName()方法加载数据库驱动,然后调用DriverManager.getConnection()方法建立连接.

连接池方式

连接池解决方案是在应用程序启动时就预先建立多个数据库连接对象,然后将连接对象保存到连接池中。当客户请求到来时,从池中取出一个连接对象为客户服务。当请求完成时,客户程序调用close()方法,将连接对象放回池中.对于多于连接池中连接数的请求,排队等待。应用程序还可根据连接池中连接的使用率,动态增加或减少池中的连接数。

传统方式存在问题

Connection对象在每次执行DML和DQL的过程中都要创建一次,DML和DQL执行完毕后,connection对象都会被销毁. connection对象是可以反复使用的,没有必要每次都创建新的.该对象的创建和销毁都是比较消耗系统资源的,如何实现connection对象的反复使用呢?使用连接池技术实现.

连接池的优势

1预先准备一些链接对象,放入连接池中,当多个线程并发执行时,可以避免短时间内一次性大量创建链接对象,减少计算机单位时间内的运算压力,提高程序的响应速度

2实现链接对象的反复使用,可以大大减少链接对象的创建次数,减少资源的消耗

具体实现如下

连接池代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package com.excepenxi.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;

public class MyConnectionPool {
private static String driver ="com.mysql.cj.jdbc.Driver";
private static String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
private static String user="root";
private static String password="root";
private static int initSize=1;
private static int maxSize=1;

private static LinkedList<Connection> pool;

static{
// 加载驱动
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 初始化pool
pool=new LinkedList<Connection>();
// 创建5个链接对象
for (int i = 0; i <initSize ; i++) {
Connection connection = initConnection();
if(null != connection){
pool.add(connection);
System.out.println("初始化连接"+connection.hashCode()+"放入连接池");
}
}
}

// 私有的初始化一个链接对象的方法
private static Connection initConnection(){
try {
return DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}

// 共有的向外界提供链接对象的
public static Connection getConnection(){
Connection connection =null;
if(pool.size()>0){
connection= pool.removeFirst();// 移除集合中的第一个元素
System.out.println("连接池中还有连接:"+connection.hashCode());
}else{
connection = initConnection();
System.out.println("连接池空,创建新连接:"+connection.hashCode());
}
return connection;
}

// 共有的向连接池归还连接对象的方法
public static void returnConnection(Connection connection){
if(null != connection){
try {
if(!connection.isClosed()){
if(pool.size()<maxSize){
try {
connection.setAutoCommit(true);// 调整事务状态
System.out.println("设置连接:"+connection.hashCode()+"自动提交为true");
} catch (SQLException e) {
e.printStackTrace();
}
pool.addLast(connection);
System.out.println("连接池未满,归还连接:"+connection.hashCode());
}else{
try {
connection.close();
System.out.println("连接池满了,关闭连接:"+connection.hashCode());
} catch (SQLException e) {
e.printStackTrace();
}
}
}else{
System.out.println("连接:"+connection.hashCode()+"已经关闭,无需归还");
}
} catch (SQLException e) {
e.printStackTrace();
}
}else{
System.out.println("传入的连接为null,不可归还");
}
}
}
BaseDao代码修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package com.excepenxi.dao;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public abstract class BaseDao {

// 增删改
public int baseUpdate(String sql,Object ... args){
Connection connection = null;
PreparedStatement preparedStatement=null;
int rows=0;

try{
connection = MyConnectionPool.getConnection();

preparedStatement = connection.prepareStatement(sql);
//设置参数 setObject自动判断数据类型
for (int i = 0; i <args.length ; i++) {
preparedStatement.setObject(i+1, args[i]);
}
//执行CURD
rows =preparedStatement.executeUpdate();// 这里不需要再传入SQL语句
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
MyConnectionPool.returnConnection(connection);
}
return rows;
}

// 查
public List baseQuery(Class clazz, String sql, Object ... args) {
// 查询名字中包含字母A的员工信息
Connection connection = null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
List list =null;
try{
connection = MyConnectionPool.getConnection();
preparedStatement = connection.prepareStatement(sql);//这里已经传入SQL语句
//设置参数
for (int i = 0; i <args.length ; i++) {
preparedStatement.setObject(i+1, args[i]);
}
//执行CURD
resultSet = preparedStatement.executeQuery();// 这里不需要再传入SQL语句
list=new ArrayList() ;
// 根据字节码获取所有 的属性
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);// 设置属性可以 访问
}
while(resultSet.next()){
// 通过反射创建对象
Object obj = clazz.newInstance();//默认在通过反射调用对象的空参构造方法
for (Field field : fields) {// 临时用Field设置属性
String fieldName = field.getName();// empno ename job .... ...
Object data = resultSet.getObject(fieldName);
field.set(obj,data);
}
list.add(obj);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != resultSet){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null != preparedStatement){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
MyConnectionPool.returnConnection(connection);
}
return list;
}
}
运行测试

Test1、EmpManageSystem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.excepenxi.test1;

import com.excepenxi.dao.MyConnectionPool;
import java.sql.Connection;

public class Test1 {
public static void main(String[] args) {
Connection connection1 = MyConnectionPool.getConnection();
Connection connection2 = MyConnectionPool.getConnection();
Connection connection3 = MyConnectionPool.getConnection();

MyConnectionPool.returnConnection(connection1);
MyConnectionPool.returnConnection(connection2);
MyConnectionPool.returnConnection(connection3);
//MyConnectionPool.returnConnection(null);
}
}

测试结果

连接池(优化参数)

配置文件优化连接池参数存储

新增文件

1
2
3
4
5
6
7
8
9
## key=value
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
user=root
password=root
## 初始容量
initSize=1
## 最大容量
maxSize=1
优化连接池代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package com.excepenxi.dao;

import com.excepenxi.util.PropertiesUtil;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;

public class MyConnectionPool {
private static String driver;
private static String url;
private static String user;
private static String password;
private static int initSize;
private static int maxSize;

private static LinkedList<Connection> pool;

static{
// 初始化参数
PropertiesUtil propertiesUtil=new PropertiesUtil("/jdbc.properties");
driver=propertiesUtil.getProperties("driver");
url=propertiesUtil.getProperties("url");
user=propertiesUtil.getProperties("user");
password=propertiesUtil.getProperties("password");
initSize=Integer.parseInt(propertiesUtil.getProperties("initSize"));
maxSize=Integer.parseInt(propertiesUtil.getProperties("maxSize"));

// 加载驱动
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 初始化pool
pool=new LinkedList<Connection>();
// 创建5个链接对象
for (int i = 0; i <initSize ; i++) {
Connection connection = initConnection();
if(null != connection){
pool.add(connection);
System.out.println("初始化连接"+connection.hashCode()+"放入连接池");
}
}
}

// 私有的初始化一个链接对象的方法
private static Connection initConnection(){
try {
return DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}

// 共有的向外界提供链接对象的
public static Connection getConnection(){
Connection connection =null;
if(pool.size()>0){
connection= pool.removeFirst();// 移除集合中的第一个元素
System.out.println("连接池中还有连接:"+connection.hashCode());
}else{
connection = initConnection();
System.out.println("连接池空,创建新连接:"+connection.hashCode());
}
return connection;
}

// 共有的向连接池归还连接对象的方法
public static void returnConnection(Connection connection){
if(null != connection){
try {
if(!connection.isClosed()){
if(pool.size()<maxSize){
try {
connection.setAutoCommit(true);// 调整事务状态
System.out.println("设置连接:"+connection.hashCode()+"自动提交为true");
} catch (SQLException e) {
e.printStackTrace();
}
pool.addLast(connection);
System.out.println("连接池未满,归还连接:"+connection.hashCode());
}else{
try {
connection.close();
System.out.println("连接池满了,关闭连接:"+connection.hashCode());
} catch (SQLException e) {
e.printStackTrace();
}
}
}else{
System.out.println("连接:"+connection.hashCode()+"已经关闭,无需归还");
}
} catch (SQLException e) {
e.printStackTrace();
}
}else{
System.out.println("传入的连接为null,不可归还");
}
}
}
工具类代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.excepenxi.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

// 工具类
public class PropertiesUtil {
private Properties properties;

public PropertiesUtil(String path){
properties=new Properties();
InputStream inputStream = this.getClass().getResourceAsStream(path);
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}

public String getProperties(String key){
return properties.getProperty(key);
}
}
运行测试

Test2、EmpManageSystem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.excepenxi.test1;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class Test2 {
public static void main(String[] args) {
Properties properties=new Properties();
InputStream inputStream = Test2.class.getResourceAsStream("/jdbc.properties"); // 指向字节码根路径下的一个文件的IO流
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
String property = properties.getProperty("driver");
System.out.println(property);
}
}
1
// EmpManageSystem 代码不变

log4j日志框架

理论

如何记录日志

  • 方式1:System.out.println(…..) e.printStackTrace();

  • 缺点:不是保存到文件,不能长久存储

  • 方式2:IO流 将System.out.println(…..) e.printStackTrace();写入文件

  • 缺点:操作繁琐,IO流操作容易阻塞线程,日志没有等级,日志的格式不能很好的定制,要想实行编程复杂

  • 方式3:使用现成的日志框架,比如log4j

  • 优点:1 长久保存;2 有等级;3 格式可以很好的定制;4 代码编写简单

log4j日志的级别

  • FATAL: 指出现非常严重的错误事件,这些错误可能导致应用程序异常中止

  • ERROR: 指虽有错误,但仍允许应用程序继续运行

  • WARN: 指运行环境潜藏着危害

  • INFO: 指报告信息,这些信息在粗粒度级别上突出显示应用程序的进程

  • DEBUG: 指细粒度信息事件,对于应用程序的调试是最有用的

理解日志格式化字符的含义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
%p:输出日志信息的优先级,即DEBUG,INFO,WARN,ERROR,FATAL。

%d:输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,如:%d{yyyy/MM/dd HH:mm:ss,SSS}。

%r:输出自应用程序启动到输出该log信息耗费的毫秒数。

%t:输出产生该日志事件的线程名。

%l:输出日志事件的发生位置,相当于%c.%M(%F:%L)的组合,包括类全名、方法、文件名以及在代码中的行数。例如

test.TestLog4j.main(TestLog4j.java:10)。
%c:输出日志信息所属的类目,通常就是所在类的全名。
%M:输出产生日志信息的方法名。
%F:输出日志消息产生时所在的文件名称。
%L::输出代码中的行号。
%m::输出代码中指定的具体日志信息。
%n:输出一个回车换行符,Windows平台为"rn",Unix平台为"n"。
%x:输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
%%:输出一个"%"字符。
使用log4j记录日志

  1. 加入jar包 log4j-1.2.8.jar

  2. 加入属性文件 src 下 log4j.properties

  • log4j.rootLogger=日志级别(debug),控制台输出(stdout),输出文件(logfile)
1
2
3
4
5
6
7
8
9
10
log4j.rootLogger=info,stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout

log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=d:/excepenxi.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n
  • 通过属性文件理解log4j的主要API

  • Appender 日志目的地 :ConsoleAppender FileAppender

  • Layout 日志格式化器 :SimpleLayout PatternLayout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.excepenxi.test1;

import org.apache.log4j.Logger;

public class TestLog4j {
public static void main(String[] args) {
// 1.字符串一般传入一个类的全路径名 "com.excepenxi.dao.impl.EmpDaoImpl"
// 2.传入一个类的字节码 TestLog4j.class
Logger logger = Logger.getLogger(TestLog4j.class);

// 日志级别
logger.fatal("fatal message");
logger.error("error message");
logger.warn("warn message");
logger.info("info message");
logger.debug("debug message");

// 打印异常信息
try {
int i = 1/0; // 选中这行内容 Ctrl+Alt+T
} catch (Exception e) {
logger.warn("程序捕获到了异常",e);
}
}
}

运行测试

  1. 代码中记录日志
1
2
3
4
5
6
7
//创建一个日志记录器
private static final Logger logger = Logger.getLogger(DBUtil.class.getName());

//在合适的地方添加日志
logger.info("正确的读取了属性文件:"+prop);
logger.debug("正确的关闭了结果集");
logger.error("DML操作错误:"+e);
测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package com.excepenxi.dao;

import com.excepenxi.util.PropertiesUtil;
import org.apache.log4j.Logger;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;

public class MyConnectionPool {
private static String driver;
private static String url;
private static String user;
private static String password;
private static int initSize;
private static int maxSize;
// 注意 Logger 别导包错误
private static Logger logger;
private static LinkedList<Connection> pool;

static{
logger=Logger.getLogger(MyConnectionPool.class);
// 初始化参数
PropertiesUtil propertiesUtil=new PropertiesUtil("/jdbc.properties");
driver=propertiesUtil.getProperties("driver");
url=propertiesUtil.getProperties("url");
user=propertiesUtil.getProperties("user");
password=propertiesUtil.getProperties("password");
initSize=Integer.parseInt(propertiesUtil.getProperties("initSize"));
maxSize=Integer.parseInt(propertiesUtil.getProperties("maxSize"));

// 加载驱动
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
logger.fatal("找不到数据库驱动类"+driver,e);
}
// 初始化pool
pool=new LinkedList<Connection>();
// 创建5个链接对象
for (int i = 0; i <initSize ; i++) {
Connection connection = initConnection();
if(null != connection){
pool.add(connection);
logger.info("初始化连接"+connection.hashCode()+"放入连接池");
}
}
}

// 私有的初始化一个链接对象的方法
private static Connection initConnection(){
try {
return DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
logger.fatal("初始化连接异常",e);
}
return null;
}

// 共有的向外界提供链接对象的
public static Connection getConnection(){
Connection connection =null;
if(pool.size()>0){
connection= pool.removeFirst();// 移除集合中的第一个元素
logger.info("连接池中还有连接:"+connection.hashCode());
}else{
connection = initConnection();
logger.info("连接池空,创建新连接:"+connection.hashCode());
}
return connection;
}

// 共有的向连接池归还连接对象的方法
public static void returnConnection(Connection connection){
if(null != connection){
try {
if(!connection.isClosed()){
if(pool.size()<maxSize){
try {
connection.setAutoCommit(true);// 调整事务状态
logger.debug("设置连接:"+connection.hashCode()+"自动提交为true");
} catch (SQLException e) {
e.printStackTrace();
}
pool.addLast(connection);
logger.info("连接池未满,归还连接:"+connection.hashCode());
}else{
try {
connection.close();
logger.info("连接池满了,关闭连接:"+connection.hashCode());
} catch (SQLException e) {
e.printStackTrace();
}
}
}else{
logger.info("连接:"+connection.hashCode()+"已经关闭,无需归还");
}
} catch (SQLException e) {
e.printStackTrace();
}
}else{
logger.warn("传入的连接为null,不可归还");
}
}
}

测试结果

三大范式

介绍

必须保证数据库设计的合理性,对数据库设计总结的一些经验性的规范,称之为范式(NF= NormalForm)

  1. 数据库设计关系整个系统的架构,关系到后续开发效率和运行效率

  2. 数据库的设计主要包含了设计表结构和表之间的联系

如何是合理数据库

  1. 结构合理

  2. 冗余较小

  3. 尽量避免插入删除修改异常

如何才能保证数据库设计水平

  1. 遵循一定的规则

  2. 在关系型数据库中这种规则就称为范式

什么是范式(NF= NormalForm)

  1. 范式是符合某一种设计要求的总结。

  2. 要想设计一个结构合理的关系型数据库,必须满足一定的范式。

范式分类
  • 第一范式:列原子性

  • 第二范式:数据和联合主键完全相关性

  • 第三范式:数据和主键直接相关性

    1. Boyce Codd范式=BCNF
    2. 由Boyce和Codd提出的
    3. 比3NF又进了一步
    4. 通常认为是修正的第三范式
  • 第四范式

  • 第五范式

各个范式是依次嵌套包含的;范式越高,设计质量越高,在现实设计中也越难实现

一般数据库设计,只要达到第三范式,即可避免异常的出现

范式

第一范式

要求

  • 最基本的范式

  • 数据库表每一列都是不可分割基本数据项,同一列中不能有多个值

  • 简单说就是要确保每列保持原子性

  • 第一范式的合理遵循需要根据系统的实际需求来定

第二范式

要求

  • 第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(言)

  • 即在一个数据库表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。

第三范式

要求

  • 确保数据表中的每一列数据都和主键直接相关,而不能间接相关

  • 属性不依赖于其他非主属性。

范式总结

优点

  • 结构合理

  • 冗余较小

  • 尽量避免插入删除修改异常

缺点

  • 性能降低
  • 多表查询比单表查询速度慢

数据库的设计应该根据当前情况和需求做出灵活的处理。

  • 在实际设计中,要整体遵循范式理论。

  • 如果在某些特定的情况下还死死遵循范式也是不可取的,因为可能降低数据库的效率,此时可以适当增加冗余而提高性能

示例

  • 比如经常购物车条目的中除了条目编号,商品编号,商品数量外,可以增加经常使用的商品名称,商品价格等

  • 范式是指导数据设计的规范化理论,可以保证数据库设计质量

  • 第一范式:字段不能再分

  • 第二范式:不存在局部依赖

  • 第三范式:不含传递依赖(间接依赖)

  • 使用范式可以减少冗余,但是会降低性能

  • 特定表的的设计可以违反第三范式,增加冗余提高性能

数据库之间的三大关系

  • 一对一 :A表中的一条数据对应B表中的一条数据

  • 一对多:A表中的一条数据对应B表中的多条数据

  • 多对多
    • A表中对应B表中多条数据,同样B表中对应A表中多条数据
    • 多对多需要通过中间表体现关系
    • 中间表讲多对多的关系转变成两个一对多



----------- 本文结束 -----------




Buy me a coffee.