在成熟的WEB应用中,数据库是必不可少的。而在用于记录用户撰写的某些记录、微博类的网站中,更是需要数据库的支持。有了数据库之后的web应用一个最大的进步就是任何时候重启应用之后,之前的保存数据不会丢失。本文以MySQL数据库为例演示了将传统内存记录数据的模式换成数据库记录数据的过程。
在我的一个应用的alpha版中,为了方便,在服务器端后台程序中用了一个HashMap来保存用户的记录,每一条记录中包含一个日期,一个用户名,一个记录内容,以及该条记录接受到的回复的内容(用另外一个HashMap保存起来的)。java代码中的property是这样的:
public class UserContent {
private final String updateData;
private final String content;
private final String userName;
private Map<String, UserContent> responses = new HashMap<String, UserContent>();
}
可以看到在回复的内容 responses 这个Map中,每一个value是一个UserContent类的对象。
在beta版中,需要将每一条记录保存在数据库中,以防止在重启java虚拟机的时候记录不会像alpha版中一样被清掉。
首先,需要弄个数据库,比如MySQL这个数据库。获得这个数据库比较简单,直奔其官网 http://dev.mysql.com/downloads/mysql/ 弄个 MySQL Community Server下来安装就OK了。这个时候的MySQL就像刚下载了JDK的java一样,已经可以使用了。但是就像JAVA缺少了Eclipse、Intellij 等这种可视性强的编辑环境之后很难使用一样,此时的mySQL已经可以接受SQL语句的操作建表,增删查改了,但是没有可视化的视图是很难使用的。这时候可以使用MySQL自带的官方可视化软件 MySQLWorkbench,地址是: http://dev.mysql.com/downloads/tools/workbench/
自带的这个MySQLWorkbench有很多右键选项,以及对于数据库中表的可视化显示。很多右键菜单在使用之后可以看到实际上执行的SQL代码,如创建表,查看表中数据,修改数据等。 使用MySQLWorkbench的时候需要注意的一点是,在进入该软件后新建一个数据库的时候,会有一个Connection Name的设置,但是在JDBC中使用的时候可以发现其实这个名字并不起作用,这个所谓的Connection Name 也绝对不能取代localhost这个主机名。
进入MySQLWorkbench之后,新建schema,新建表以及在表中新建字段等操作都比较简单。对表做了修改之后点击apply可以看到实际执行的SQL代码,非常有利于对于SQL语法的学习。
为了代替整个UserContent类的作用,我在我的数据库CoreDataBase中新建了两张表,第一张表用于记录单条记录的信息,表的字段包含id,username,constructdate和content。
第二张表则用来记录单条的response,每一条response在表中对应一行。这个表的字段有:id,responser,contentid,responsedate,replycontent。其中contentid指明该条response所属的原始UserContent的id。在两个表中各自的id都是唯一非负自增长的。
至此,数据库方面需要做的工作已经OK了,另外一个大的方面是在java代码中调用,控制这个数据库。此时需要使用到java与数据库的接口JDBC了。
在网上有很多讲解怎么使用JDBC的blog,我就简单的写下我的用法。在一个专门用于连接我的数据库的类中,有一个建立连接的方法:
private void connectDatabase() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost/CoreBase", "root", "");
statement = connection.createStatement();
}
现在创建一条UserContent就可以用如下的方法了:
public void addContent(String userName, String content, String date) throws SQLException, ClassNotFoundException {
connectDatabase();
String values = format(userName)+","+format(content)+","+format(date);
String initSQL = "INSERT INTO CoreBase.MainContent(username,content,constructdate) " +
"values(" + values + ")";
statement.execute(initSQL);
connection.close();
}
其中最核心的代码是statement执行SQL语句的execute方法。在创建,删除以及修改的时候可以不需要返回值所以调用Statement的execute方法,而在查询的时候需要有返回值,因此采用一个ResultSet类对象来接受Statement类executeQuery方法的返回值。
添加一条response记录的执行代码和addContent差不多,因为response完全保存在另外一张表中,只需要获取response应该填入的contentid获取到填入表中即可。
最复杂的部分来自于在读取UserContent的时候,需要将response表中所有contentid与这一条UserContent中的id相同的记录都获取到。java代码为:
public Map<String, UserContent> getUserContent(String username) throws SQLException, ClassNotFoundException {
connectDatabase();
Map<String,UserContent> resultMap = new HashMap<String, UserContent>();
// Construct Initial User Content Without Reply.
String queryKEYs = "SELECT id,username,content,constructdate FROM CoreBase.MainContent WHERE username="+format(username);
resultSet = statement.executeQuery(queryKEYs);
while (resultSet.next()){
String id = resultSet.getString(1);
String user = resultSet.getString(2);
String content = resultSet.getString(3);
String date = resultSet.getString(4);
UserContent userContent = new UserContent(user,content,date);
resultMap.put(id,userContent);
}
// Add Response Content
for (String mainContentKey : resultMap.keySet()){
Map<String,UserContent> responseMap = new HashMap<String, UserContent>();
String queryReply = "SELECT id,responser,replycontent,responsedate FROM CoreBase.Reply WHERE contentid="+format(mainContentKey);
resultSet = statement.executeQuery(queryReply);
while (resultSet.next()){
String id = resultSet.getString(1);
String user = resultSet.getString(2);
String content = resultSet.getString(3);
String date = resultSet.getString(4);
UserContent userContent = new UserContent(user,content,date);
responseMap.put(id,userContent);
}
resultMap.get(mainContentKey).setResponses(responseMap);
}
connection.close();
return resultMap;
}
代码略显笨拙,但是有一点好的结果是:WORK!
最后还有一点,在某些blog中会提到需要引入JDBC包或者MySQL-connect包之类的东西。在maven项目中可能会需要加入mysql的依赖:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
本例子来源于开源项目Vaboo:https://github.com/SonlyF5020/MyVaboo