<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh">
	<id>https://game.etao.net/w/index.php?action=history&amp;feed=atom&amp;title=Low_Level_Database_Access</id>
	<title>Low Level Database Access - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://game.etao.net/w/index.php?action=history&amp;feed=atom&amp;title=Low_Level_Database_Access"/>
	<link rel="alternate" type="text/html" href="https://game.etao.net/w/index.php?title=Low_Level_Database_Access&amp;action=history"/>
	<updated>2026-05-05T16:00:42Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://game.etao.net/w/index.php?title=Low_Level_Database_Access&amp;diff=148&amp;oldid=prev</id>
		<title>2020年4月27日 (一) 07:49 115.192.141.63</title>
		<link rel="alternate" type="text/html" href="https://game.etao.net/w/index.php?title=Low_Level_Database_Access&amp;diff=148&amp;oldid=prev"/>
		<updated>2020-04-27T07:49:25Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Navigation for Marauroa Top|Internals}}&lt;br /&gt;
{{Navigation for Marauroa Developers}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Database Access}}&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
本文介绍了Marauroa内部如何访问数据库以及如何添加自己的表. Marauroa数据库的表结构请参阅 [[Marauroa Database Structure]]. 你也许需要先看一下 [[High Level Database Access]] . 它说明了从程序代码访问数据库的高级API.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 数据库抽象 ==&lt;br /&gt;
&lt;br /&gt;
低级数据库访问代码封装在DAO类中。 只有这些类使用JDBC将SQL查询发送到数据库.&lt;br /&gt;
&lt;br /&gt;
通过以下位置获取DBTransaction对象来启动事务 [http://stendhal.game-host.org/hudson/job/marauroa_HEAD/javadoc/marauroa/server/db/TransactionPool.html TransactionPool]. 然后使用 [http://stendhal.game-host.org/hudson/job/marauroa_HEAD/javadoc/marauroa/server/db/DBTransaction.html DBTransaction] 对象的方法与数据库交谈. 请注意，许多方法都希望将参数映射作为第二个参数. 这使您可以在SQL语句中用 &amp;lt;nowiki&amp;gt;[variables]&amp;lt;/nowiki&amp;gt; 无需担心转义输入参数以防止SQL注入攻击.&lt;br /&gt;
&lt;br /&gt;
但是，DBTransaction本身不执行SQL语句。 它在内部将它们转发到DatabaseAdapter的子类。 这是一个非常小的抽象层，用于隐藏不同数据库系统使用的SQL方言. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Classdiagram_database_access.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 编写你自己的 DAO ==&lt;br /&gt;
&lt;br /&gt;
编写自己的DAO类时，请遵循以下规则&lt;br /&gt;
* 使用 &amp;lt;nowiki&amp;gt;[variables]&amp;lt;/nowiki&amp;gt; 传送不受信任的数据，因为它将被自动转义以防止SQL注入攻击&lt;br /&gt;
* 在DAORegistry (see next section) 中注册你的类，而不是直接调用构造函数&lt;br /&gt;
* 使用 dbTransaction.getLastInsertId() 而不是 &amp;quot;select @@identity&amp;quot; 并在相关插入内容后直接调用&lt;br /&gt;
* 尝试避免使用数据库系统特定的代码（特别注意通常支持的SQL函数）&lt;br /&gt;
* 为所有方法提供两个签名: 一个以DBTransaction作为第一个参数，另一个没有。 第二个应该只是获取事务本身，调用第一个，然后提交/回滚事务&lt;br /&gt;
&lt;br /&gt;
== 扩展已有的 DAO ==&lt;br /&gt;
&lt;br /&gt;
DAO类永远不能直接实例化。 相反，您应该（并且marauroa确实）使用DAORegistry。 这使您可以编写marauroa提供的DAO的子类并进行注册。 如果您熟悉Spring，这是一个类似的概念。 但是没有所有大量的xml配置文件，参数注入和接口，只有一个实现.&lt;br /&gt;
&lt;br /&gt;
假设您想用SomeGameCharacterDAO类将CharacterDAO子类化:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
     public class SomeGameCharacterDAO extends CharacterDAO {&lt;br /&gt;
     ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
您只需要简单地注册为&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
     DAORegistry.get().register(CharacterDAO.class, new SomeGameCharacterDAO());&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
注意：在注册调用中，第一个参数是您要替换的父类.&lt;br /&gt;
&lt;br /&gt;
== Adding support for another database system ==&lt;br /&gt;
&lt;br /&gt;
Marauroa尝试严格遵循SQL标准。 但是，不可能编写适用于所有通用数据库系统的SQL语句，因为每个数据库系统都有自己的方言。 幸运的是只有微小的差异. 例如 MySQL 要求 &amp;quot;create table&amp;quot; 语句以 &amp;quot;TYPE=InnoDB&amp;quot; 结束. Marauroa 使用 [http://stendhal.game-host.org/hudson/job/marauroa_HEAD/javadoc/marauroa/server/db/adapter/DatabaseAdapter.html DatabaseAdapter] 接口在隐藏这些差异.&lt;br /&gt;
&lt;br /&gt;
已经为此接口提供了一个默认实现，即 [http://stendhal.game-host.org/hudson/job/marauroa_HEAD/javadoc/marauroa/server/db/adapter/AbstractDatabaseAdapter.html AbstractDatabaseAdapter] ([http://arianne.cvs.sf.net/viewvc/arianne/marauroa/src/marauroa/server/db/adapter/AbstractDatabaseAdapter.java?view=markup source]). And we provide a MySQLDatabaseAdapter ([http://arianne.cvs.sf.net/viewvc/arianne/marauroa/src/marauroa/server/db/adapter/MySQLDatabaseAdapter.java?view=markup source]) and a H2DatabaseAdapter ([http://arianne.cvs.sf.net/viewvc/arianne/marauroa/src/marauroa/server/db/adapter/H2DatabaseAdapter.java?view=markup source]), too.&lt;br /&gt;
&lt;br /&gt;
请查阅这些java文件。 为其他数据库系统添加更多适配器应该非常容易。 注意：我们对接受这些适配器并将其添加到主要代码库非常感兴趣。&lt;br /&gt;
&lt;br /&gt;
== 更新数据库结构 ==&lt;br /&gt;
&lt;br /&gt;
如果添加表和列，则最好在服务器启动时自动创建它们。 JDBCHelper类中的runSQLScript（）方法可用于执行SQL脚本。 注意：应该使用“create table if not exists”代替简单的“create table”，以便可以在每个服务器启动时执行脚本，而不必担心表是否已经存在.&lt;br /&gt;
&lt;br /&gt;
不幸的是，SQL中没有“如果不存在则创建列”子句。 因此，如果需要将列添加到现有表中，则需要自己进行检查.&lt;br /&gt;
&lt;br /&gt;
以下示例显示了用于将新结果列添加到passwordChange表的代码。 在添加该列之前，仅记录成功的密码更改。 因此，结果列应初始化为1.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
if (!transaction.doesColumnExist(&amp;quot;passwordChange&amp;quot;, &amp;quot;result&amp;quot;)) {&lt;br /&gt;
    transaction.execute(&amp;quot;ALTER TABLE passwordChange ADD COLUMN (result TINYINT);&amp;quot;, null);&lt;br /&gt;
    transaction.execute(&amp;quot;UPDATE passwordChange SET result=1 WHERE result IS NULL&amp;quot;, null);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
{{#breadcrumbs: [[Marauroa]] | [[Navigation for Marauroa Developers|Internals]] | [[Low Level Database Access|低级数据库访问]] }}&lt;/div&gt;</summary>
		<author><name>115.192.141.63</name></author>
	</entry>
</feed>