Java for Web学习笔记(九六):持久化初探(1)数据存储

来源:互联网 发布:适合mac的杀毒软件 编辑:程序博客网 时间:2024/06/06 04:00

数据的存储介质

flat-file entity storage

不同的entity可能存放在不同的目录,每个entity就是目录下的一个文件,名字是代理键( surrogate key),也就是索引,方便定位。文件格式多样,可能是直接Java对象序列化,可能是XML,JSON。

读写entity,需要打开文件和关闭文件,因此效率低下,且不支持代理键之外的索引。一般用于存储少量且基本的数据,例如应用配置。

structured file storage

结构化文件将一个文件是一个entity type,里面具有这个类型的多个(所有)entity的数据。在根据代理键SK读取某个entity时性能会有些问题,通常会另外有一个小的index文件,来帮助快速在大的数据文件中定位。

这和关系型数据库中的ISAM(Indexed Sequential Access Method)很相似,而早期的一些数据库就是这样实现的,如Btrieve。只是在结构化文件中结构是私有,并由程序代码来解析,而数据库是通用的;更重要的,关系型数据库具有不同entity之间的关联,而结构化文件不能提供。如果我们在MySQL中引擎采用了ISAM,表格是不支持外键的。

Relational Database systems

关系数据库是最常使用的数据库,如MySQL。entity作为record存放在table中,table就是一个entity type(当然,复杂的entity可能需要多个表格),表格由严格的schema来定义名字,类型,限制,key。使用ANSI标准的Structured Query Language (SQL)来操作表格schema和数据。然而,没有一种关系型数据库是完全遵守ANSI标准,大多由自己的扩展,这使得在不同的关系型数据库中迁移存在困难。

在Java中使用JDBC(Java Database Connectivity),为了避免每次访问数据库,都重新打开和关闭数据库的连接,第三方jar提供了连接池的管理,最常用的就是C3P0[1]。

Object-Oriented Databases

对象型数据库尝试解决面向对象和关系型数据库的关联问题。既想使用SQL,又想获得对象。但鱼和熊掌很难兼得。如何确保对象的继承关系,如何有方便检索,能否不使用SQL的私有扩展。这些都是问题,因此,虽然一直存在对象性数据库,却一直未能广泛使用。

schema-less Database systems

无模式数据库,也就是没有严格的schema。NoSQL就是描述这样的数据库,在近年来发展很快。它解决了关系型数据库中灵活field和对象集成等问题。

面向文档数据库
有很多类型的NoSQL数据库,最常见的是面向文档数据库(document-oriented database),数据存放格式一般为XML,JSON(或BSON)。一个文件对应关系数据库中的record,一个collection对应关系型数据库中的table。和关系型数据看相比,其特点是insert效率要高得多得多,但是查询没那么快,但存储的数据量大很多很多。流行的包括MongoDB,Apache Couch DB和Couchbase Server。
key-value store
以某种方式存放键值对,类似Java的Map<String, String>,或者Map<String, List<String>>。有名的键值存储数据库有:Apache Cassandra, Freebase, Amazon DynamoDB, memcache, Redis, Apache River, Couchbase和MongoDB。有些文件数据库也同时采用键值存储。
图形数据库
重点在对象关系。对象有属性,以及与其他对象的关系,而关系是有属性的。数据的存储和表示为图,实体间的关联是自然的。最流行的图形数据库是Neo4j。

NoSQL数据库没有类似ANSI SQL标准,没有NoSQL数据库都有自己的客户端,一方面通用性是确定,但是大多数的client都可以直接从数据库中读写对象,而不需要如关系型数据库那样,将POJO类映射到表,将属性映射到列。

无映射的传统方式

MySQL的test数据库中有一个很简单的students表格,实际表格的列会多很多。

CREATE TABLE `students` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(64) NOT NULL,  `score` int(11) NOT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8
我们使用了C3p0作为数据库的连接管理池,以前写过C3p0MysqlManager[2],可以利用,重点看看读写表格的代码:
//【1】读取例子,Student的POJO只有三个属性,相对简单,如果有十个,数十个呢,代码就很啰嗦了。public Student getStudent(long id) throws SQLException{try(Connection connection = C3p0MysqlManager.getConnection(DATA_SOURCE_NAME);PreparedStatement ps = connection.prepareStatement("SELECT * FROM test.students WHERE `id`=?");){ps.setLong(1, id);try(ResultSet rs = ps.executeQuery()){if(!rs.next())return null;Student student = new Student();student.setId(id);student.setName(rs.getString("name"));student.setScore(rs.getInt("score"));return student;}}}//【2】增加entity的例子,特别地,在此演示了如何获取自动增加的流水号public void addStudent( String name, int score) throws Exception{Student student = new Student();student.setName(name);student.setScore(score);try(Connection connection = C3p0MysqlManager.getConnection(DATA_SOURCE_NAME);PreparedStatement ps = connection.prepareStatement("INSERT into test.students(`name`,`score`) values(?,?)",                                                   Statement.RETURN_GENERATED_KEYS );){ ps.setNString(1, student.getName());ps.setInt(2, student.getScore());if(ps.executeUpdate() != 1)throw new Exception("Failed to insert record.");try(ResultSet r = ps.getGeneratedKeys()){if(!r.next())throw new Exception("Failed to retrieve ID.");student.setId(r.getLong(1));  //也可以是r.getLong("GENERATED_KEY"),因为r只有1列,用columnIndex更便捷}}}
通过抓包观察mysql的交互(url中设置useSSL=false),无论我们在ps中设置为Statement.RETURN_GENERATED_KEYS还是Statement.NO_GENERATED_KEYS,消息报文是一样的,均带有LAST INSERT ID,只是是否允许代码中通过ps.getGeneratedKeys()来获取。



相关链接: 我的Professional Java for Web Applications相关文章

阅读全文
0 0
原创粉丝点击