bug修复
前面我们的项目中,Blog类和User类的id属性设置为long类型,实际上应该设置为Long类型会更好。因为:
- Java中Long 类型建立的时候如果没赋值,会默认给一个null.而long类型建立的时候如果没有赋值,则是0L。而id属性是数据库自动去填充值的,不应该有默认值,我们可以通过是否为null来判断是否存在记录。
- Long提供了很多API, 比如查询、赋空值等简便, 可以利用Long本身的优化;如你使用Long.valueOf时 可以利用缓存的-128至127之间的值; 还有从使用hibernate、el表达式等都是包装类型,减少了装箱/拆箱;
我们还得修改模型类的getId、setId的返回类型。
同理,模型类比如购物车Cart,它的字段页应该是Integer而不是int。相应的我们要修改那些传入参数long参数对应的修改为Long才行。一般模型类中的方法参数最好都是封装类型而不是基本类型。
model类里面去掉id = count++;
因为id自增交由数据库去完成,所以我们不必使用java代码去实现。所以我们要去修改User模型类和Blog模型类。
User模型类需要添加新的字段description
相应的修改用户仓库初始化代码和用户模型类构造器
数据库通用操作封装到DBHleper工具类
package com.jspblog.utils;
import com.jspblog.model.Blog;
import com.jspblog.model.Project;
import com.jspblog.model.User;
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.util.ArrayList;
import java.util.List;
public class DBHelper {
public static String driver = "com.mysql.jdbc.Driver";
public static String connectionString = "jdbc:mysql://127.0.0.1:3306/jspblog?useSSL=false";
public static String username = "root";
public static String password = "123456";
// 1、加载MYSQL驱动,这里MySQL的JDBC驱动类是com.mysql.jdbc.Driver,要求类路径中包含相应的Driver类
static {
try {
Class.forName(driver).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
}
// 2、连接到MYSQL,通过DriverManger来创建Connection对象,获取数据库连接
public static Connection getConnection() throws Exception {
return DriverManager.getConnection(connectionString, username, password);
}
// 3、创建PreparedStatement用以执行SQL语句
// 插入操作,我们希望获得插入记录后的编号,也就是返回值是id
public static Long create(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//2,连接到MYSQL
connection = getConnection();
//3,PreparedStatement用以执行SQL语句
statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
statement.executeUpdate();
//4,ResultSet用于接收SQL语句执行后的结果,更新之后我们只需要获取更新记录的id属性即可,而不是整个记录对象
resultSet = statement.getGeneratedKeys();
//5、遍历并解析结果
if (resultSet.next()) {
return resultSet.getLong(1);
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
//6,清理数据库连接相关的所有资源
clear(resultSet, statement, connection);
}
}
// 删除操作,用于remove动作
// 由于删除之后就不存在就该记录了,所以不需要遍历结果页不用返回id,直接返回数字0表示删除成功
public static int delete(String sql) {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
return statement.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
return 0;
} finally {
clear(null, statement, connection);
}
}
//查询单条记录,查询就应该返回对象,而不像插入那样只要返回id。由于查询的可能是不同对象,所以使用泛型
public static Blog queryBlog(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
if (resultSet.first()) {
int userId = resultSet.getInt("author");
User user = queryUser("select * from user where id="+userId);
Blog blog = new Blog(resultSet.getString("title"),resultSet.getString("content"),resultSet.getDate("createdTime"),user);
return blog;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
//查询单条记录,查询就应该返回对象,而不像插入那样只要返回id。由于查询的可能是不同对象,所以使用泛型
public static User queryUser(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
if (resultSet.first()) {
User user = new User(resultSet.getString("email"),resultSet.getString("username"),resultSet.getString("password"));
return user;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
//查询单条记录,查询就应该返回对象,而不像插入那样只要返回id。由于查询的可能是不同对象,所以使用泛型
public static Project queryProject(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
if (resultSet.first()) {
Project project = new Project(resultSet.getString("name"),resultSet.getString("description"),resultSet.getString("url"),resultSet.getString("logo"));
return project;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
//查询多条记录,与查询单条记录不同在于是遍历结果集放入数组中。由于查询的可能是不同对象,所以使用泛型
@SuppressWarnings("unchecked")
public static List<Blog> queryBlogList(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
List<Blog> list = new ArrayList<Blog>();
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while(resultSet.next()) {
int userId = resultSet.getInt("author");
User user = queryUser("select * from user where id="+userId);
Blog blog = new Blog(resultSet.getString("title"),resultSet.getString("content"),resultSet.getDate("createdTime"),user);
list.add(blog);
}
return list;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
//查询多条记录,与查询单条记录不同在于是遍历结果集放入数组中。由于查询的可能是不同对象,所以使用泛型
@SuppressWarnings("unchecked")
public static List<Project> queryProjectList(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
List<Project> list = new ArrayList<Project>();
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while(resultSet.next()) {
Project project = new Project(resultSet.getString("name"),resultSet.getString("description"),resultSet.getString("url"),resultSet.getString("logo"));
list.add(project);
}
return list;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
//查询多条记录,与查询单条记录不同在于是遍历结果集放入数组中。由于查询的可能是不同对象,所以使用泛型
@SuppressWarnings("unchecked")
public static List<User> queryUserList(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
List<User> list = new ArrayList<User>();
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while(resultSet.next()) {
User user = new User(resultSet.getString("email"),resultSet.getString("username"),resultSet.getString("password"),resultSet.getString("description"));
list.add(user);
}
return list;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
// 计数
//技术我们一般传入sql语句是select count(*)这样的语句,返回结果只有一条记录,页只有一个字段。该字段存的就是count的记录数目
public static int queryCount(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
//由于结果肯定只有一条记录,所以我们取出first结果即可
if (resultSet.first()) {
return resultSet.getInt(1); //获取结果集中第一列的值,count语句返回的本来就只有一个字段
}
return 0;
} catch (Exception e) {
e.printStackTrace();
return 0;
} finally {
clear(null, statement, connection);
}
}
//6、清理数据库连接相关的所有资源
private static void clear(ResultSet resultSet, Statement statement, Connection connection) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException ignored) {
}
}
}
Statement.RETURN_GENERATED_KEYS用于获取自动生成的键值,这里是自增的id号。这里也就是我们不必给数据库对象的id属性赋值,在执行sql语句的时候,添加该代码会自动往记录的id自动填入一个自动增长的数字。
getGeneratedKeys();用于获取主键,也就是上面我们执行插入语句时,自动填充的id字段的值。
新建数据库表project
执行语句如下:
CREATE TABLE `project` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`description` longtext NOT NULL,
`url` varchar(255) NOT NULL,
`logo` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
保持原Servlet不变,修改模型类
比如我们ProjectRepository类中的getAll方法:
public List<Project> getAll() {
return projects;
}
应该修改为:
public List<Project> getAll() {
return DBHelper.queryProjectList("select * from project");
}
因为Servlet获取数据是去调用模型类中的方法而已,而获取数据修改为从数据库中读取也是把模型类中获取的数据的方法体修改为调用DBHelper执行sql语句而已。在Servlet中调用的模型类方法不变,变更的是模型类方法的实现,所以自然不需要修改Servlet文件。
而且private static List<Project> projects = new ArrayList<>();属性也可以去掉了。因为之前没有数据库,所以使用一个数组属性来保存多个对象,比如我们要获取所有项目信息就去访问这个数组属性。现在有了数据库之后,要获取所有项目信息只要调用getAll()方法,得到的返回值就是一个包含所有项目信息的数组,我们直接使用方法的返回值就行,就不需要该数组属性了。
其他方法比如User、Blog等相关的多个类也做这样的修改,模型类中获取数据都改成使用DBHelper类从数据库获取数据,去掉数组属性。
修改jsp文件里面引入类的包名,由mvc改为jspblog
把模型类中的数据初始化代码删除掉,通过Navicate在数据库中录入数据
把在WEB-INF/lib目录里面放入数据库驱动的jar包mysql-connector-java-5.1.40-bin.jar
必须完成上面全部的修改后,项目才能运行。
使用JDBC先完成创建博客、博客列表、博客详情三个功能与数据库交互
到此,就完成了博客项目使用JDBC与数据库交互的全部改写,测试通过。
提交到git仓库
创建.gitignore文件,由于我们之前使用oschina自动创建的.gitignore文件,所以修改该文件后还是无法生效,应该执行下面操作清除一下缓存cache,才能使修改后的.gitignore 生效。
git rm -r --cached . #清除缓存
git add . #重新trace file
git commit -m "update .gitignore,(四)04-使用JDBC重写博客项目" #提交和注释
git push git@git.oschina.net:michael-first/jdbcblog.git master --force
为了以后提交方便,我们添加如下代码,以后提交的时候就使用jdbcblog替换代码仓库的地址,很方便
git remote add jdbcblog git@git.oschina.net:michael-first/jdbcblog.git
git push jdbcblog master