目录

我的学习分享

记录精彩的程序人生

X

Using Marauroa-Low Level Database Access

转自https://stendhalgame.org/wiki/Low_Level_Database_Access

本文介绍Marauroa如何在内部访问数据库以及如何为您自己的表添加支持。 Marauroa Database Structure解释了Marauroa数据库的表结构。 您可能希望首先查看High Level Database Access。 它解释了从程序代码访问数据库的高级API。

Database abstraction

低级别代码数据库访问代码封装在DAO类中。 只有这些类使用JDBC将SQL查询发送到数据库。

您可以通过从TransactionPool获取DBTransaction对象来启动事务。 您使用DBTransaction对象的方法与数据库进行通信。 请注意,许多方法都希望将参数映射作为第二个参数。 这允许您在SQL语句中使用[variables],而不必担心转义输入参数以防止SQL注入攻击。

但是,DBTransaction本身不执行SQL语句。 它在内部将它们转发到DatabaseAdapter的子类。 这是一个非常小的抽象层,用于隐藏不同数据库系统使用的SQL方言。

Writing your own DAO

编写自己的DAO类时请遵守以下规则:

  • use [variables] for untrusted data because it will be escaped automatically to prevent SQL Injection Attacks
  • register your class in DAORegistry (see next section) instead of calling the constructor directly
  • use dbTransaction.getLastInsertId() instead of "select @@identity" and call it directly after the insert in question
  • try to avoid database system specific code (pay special attention to generally supported SQL functions)
  • provide all methods with two signatures: One with DBTransaction as first parameter and one without. The second one should just get the transaction itself, call the first one, and commit/rollback the transaction

Extending a provided DAO

DAO类永远不应该直接实例化。 相反,你应该(和marauroa)使用DAORegistry。 这允许您编写marauroa提供的DAO的子类并将其注册。 如果您熟悉Spring,这是一个类似的概念。 但是没有大量的xml配置文件,参数注入和接口只有一个单一的实现。
想象一下,你想用你的类SomeGameCharacterDAO继承CharacterDAO:

     public class SomeGameCharacterDAO extends CharacterDAO {
     ...

你只需将其注册为

     DAORegistry.get().register(CharacterDAO.class, new SomeGameCharacterDAO());

注意:在注册器调用中,第一个参数是要替换的父类。

Adding support for another database system

Marauroa试图严格遵守SQL标准。 但是,编写适用于所有常见数据库系统的SQL语句是不可能的,因为每个数据库系统都有自己的方言。 幸运的是,只有细微的差别。 例如,MySQL要求“create table”语句以“TYPE = InnoDB”结尾。 Marauroa使用接口DatabaseAdapter来隐藏这些差异。

已经为此接口提供了名为AbstractDatabaseAdapter的默认实现。 我们也提供了MySQLDatabaseAdapter和H2DatabaseAdapter。

只是看看那些java文件。 为其他数据库系统添加更多适配器应该非常容易。 注意:我们非常有兴趣接受这些适配器并将它们添加到主代码库中。

Updating the database structure

803/5000

如果添加表和列,最好在服务器启动时自动创建它们。 类JDBCHelper中的方法runSQLScript()可用于执行SQL脚本。 注意:您应该使用“create table if not exists”而不是简单的“create table”,以便您可以在每个服务器启动时执行脚本,而不必担心表是否已存在。

不幸的是,SQL中没有“create column if not exists”子句。 因此,如果我们需要向现有表添加列,我们将需要自己进行检查。

以下示例显示用于将新结果列添加到passwordChange表的代码。 在添加该列之前,仅记录了成功的密码更改。 因此,结果列应初始化为1。

if (!transaction.doesColumnExist("passwordChange", "result")) {
    transaction.execute("ALTER TABLE passwordChange ADD COLUMN (result TINYINT);", null);
    transaction.execute("UPDATE passwordChange SET result=1 WHERE result IS NULL", null);
}