一、问题引入
1、在上一节的增删改新闻内容代码中,代码段的不同之处在于sql语句以及由sql语句带来的?填充个数,在查中,根据查的字段的不同,最终的遍历也不同。
2、同时,要是我想对新闻类型表、新闻评论表进行增删改查呢?我要做好多小的重复的工作。
3、更换数据库的时候,sql语句有细微的区别,也需要大量的修改代码。
那有什么优化的方法吗?
二、优化思路

2.1提取公共操作
获取数据连接、释放资源、增删改、查。
将上面这四个数据库的公共操作提取出来,形成一个数据库操作的基类(就如同之前的XML公共操作类)。
2.2使用接口(接口是一种规范,只定义行为)
在第一条的基础上,这样在更换数据库的时候,只需要 引入相应的基类就好了。
针对新闻操作这个例子中,将NewsDao你去一个稳定的新闻操作的接口,新闻操作写在接口的实现类中。
三、提取公共操作
示例代码:
package cn.kgc.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//数据库操作基类
public class BaseDao {
// 获取数据连接
Connection connection = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
public boolean getConnection(){
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://127.0.0.1:3306/kgcnews?characterEncoding=utf-8";
connection = DriverManager.getConnection(url, "root", "41312019");
} catch (ClassNotFoundException e) {
e.printStackTrace();
return false;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
return true;
}
// 释放资源
public boolean closeSource(){
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
return true;
}
// 增删改
public int executeUpdate(String sql, Object[] params){
int updateRows = 0;
if (this.getConnection()) {
try {
pstmt = connection.prepareStatement(sql);
// 填充占位符
for (int i = 0; i < params.length; i++) {
pstmt.setObject(i+1, params[i]);
}
updateRows = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
return updateRows;
}
//查
public ResultSet executeSQL(String sql, Object[] params){
if (this.getConnection()) {
try {
pstmt = connection.prepareStatement(sql);
// 填充占位符
for (int i = 0; i < params.length; i++) {
pstmt.setObject(i+1, params[i]);
}
rs = pstmt.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
}
return rs;
}
}
注:
1、一定要注意释放资源的顺序。
2、在接受占位符的值得时候,用object数组,该数组的下标可以与值配合,有一个一一对应关系。
3、其实就这个项目来说,做到上面的提取公共操作就已经很简化了,但是既然是公共操作,就不可能把每个操作的结果详细描述出来,比如说我要进行增加新闻的操作,我调用了父类的方法,有结果之后只能显示改变成功,不能显示“增加新闻成功”,如果要显示增加新闻成功,我需要用一个子类继承这个公共类,然后在子类中调用这个公共操作,拿到结果了之后再去显示“增加新闻成功”。
四、定义接口
接口的意义在于定义一种规范,我只要实现了这个接口,我就必须实现接口里面定义的各种方法。
就这个新闻管理系统来说,虽然只要做到提取公共操作这一步我就很简化了,但是我还是需要使用接口来保证规范性。
最终的修改如下:
接口代码:
package cn.kgc.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Date;
public interface NewsDao {
// 增加新闻信息
public void addNews(int id,int categoryId,String title,String summary,String content,String author,Date createDate);
// 删除特定新闻
public void deleteNews(int id);
// 修改特定新闻的标题
public void updateNews(int id, String title);
// 查询全部新闻信息
public void getAllNews();
// 查询特定的新闻id、标题
public void getNewsByTitle(String title);
}
公共操作类的代码见第三步。
最终的子类代码如下:
package cn.kgc.dao.implement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Date;
import cn.kgc.dao.BaseDao;
import cn.kgc.dao.NewsDao;
// 使用PreparedStatement
public class NewsDaoImpl extends BaseDao implements NewsDao {
// 增加新闻信息
public void addNews(int id,int categoryId,String title,String summary,String content,String author,Date createDate){
String sql = "INSERT INTO news_detail(id, categoryId, title, " +
"summary,content,author, createDate) VALUES(?,?,?,?,?,?,?);";
Object[] params = {id, categoryId, title, summary,content, author,createDate};
int i = this.executeUpdate(sql, params);
if (i > 0) {
System.out.println("插入资源成功!");
}
this.closeSource();
}
// 删除特定新闻
public void deleteNews(int id){
String sql = "DELETE FROM news_detail WHERE id=?";
Object[] params = {id};
int i = this.executeUpdate(sql, params);
if (i > 0){
System.out.println("删除新闻信息成功");
}
this.closeSource();
}
// 修改特定新闻的标题
public void updateNews(int id, String title){
String sql = "UPDATE news_detail SET title=? WHERE id=?";
Object[] params = {title,id};
int i = this.executeUpdate(sql, params);
if (i > 0){
System.out.println("修改新闻信息成功");
}
this.closeSource();
}
// 查询全部新闻信息
public void getAllNews(){
String sql = "SELECT id, title, author,createDate FROM news_detail";
Object[] params = {};
ResultSet rs = this.executeSQL(sql,params);
try {
while(rs.next()){
int id = rs.getInt("id");
String newsTitle = rs.getString("title");
String author = rs.getString("author");
Timestamp createdate = rs.getTimestamp("createDate");
System.out.println(id + " " + newsTitle + " " + author + " " + createdate);
}
} catch (SQLException e) {
e.printStackTrace();
}
this.closeSource();
}
// 查询特定的新闻id、标题
public void getNewsByTitle(String title){
try {
String sql = "SELECT id, title FROM news_detail where title=?";
Object[] params = {title};
ResultSet rs = this.executeSQL(sql,params);
while(rs.next()){
int id = rs.getInt("id");
String newsTitle = rs.getString("title");
System.out.println(id + " " + newsTitle);
}
}catch (SQLException e) {
e.printStackTrace();
} finally {
this.closeSource();
}
}
public static void main(String[] args) {
NewsDao dao = new NewsDaoImpl();
dao.getAllNews();
}
}
在最终的子类中,我即继承了接口,来保证我代码的规范性,又继承了父类,来使得我的最终代码里面不重复,足够的简洁。这才是一个优秀的程序员应该写的代码。