sql >> データベース >  >> RDS >> Mysql

EclipseLinkとJoda-Timeを使用してUTCで日時をデータベースに保存するにはどうすればよいですか?

    Date Javaではタイムゾーンに依存しません。常にUTC(デフォルトおよび常に)がかかりますが、Date /Timestamp JDBCドライバーを介してデータベースに渡され、JVMタイムゾーンに従って日付/時刻を解釈します。JVMタイムゾーンは、デフォルトでシステムタイムゾーン(ネイティブオペレーティングシステムゾーン)になります。

    したがって、MySQL JDBCドライバーがUTCゾーンの使用を明示的に強制されていない限り、またはJVM自体がそのゾーンを使用するように設定されていない限り、Dateは保存されません。 /Timestamp MySQL自体がdefault_time_zone='+00:00'を使用してUTCを使用するように構成されている場合でも、UTCを使用してターゲットデータベースに追加します。 my.iniで またはmy.cnf [mysqld]で セクション。 Oracleのような一部のデータベースは、タイムゾーン付きのタイムスタンプをサポートしている場合がありますが、これは私がよく知らない例外である可能性があります(現在、その環境がないため、テストされていません)。

    void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException

    これは、setTimestampInternal() MySQLJDBCドライバー実装のメソッド。

    次の2つ を参照してください。 setTimestampInternal()の呼び出し setTimestamp()の2つのオーバーロードされたバージョン内からのメソッド メソッド。

    Calendarがない場合 インスタンスはPreparedStatement#setTimestamp()で指定されます メソッドでは、デフォルトのタイムゾーンが使用されます(this.connection.getDefaultTimeZone()

    アプリケーションサーバーで接続プールを使用しているとき/接続に裏打ちされたサーブレットコンテナ/JNDIが次のようなデータソースにアクセスまたは操作しているとき

    MySQL JDBCドライバーは、目的のタイムゾーン(UTC)を使用するように強制する必要があります。次の2つのパラメーターは、接続URLのクエリ文字列を介して提供する必要があります。

    MySQL JDBCドライバーの履歴に精通していませんが、比較的古いバージョンのMySQLドライバーでは、このパラメーターuseLegacyDatetimeCode 必要ないかもしれません。したがって、その場合は自分で調整する必要があるかもしれません。

    たとえば、アプリケーションサーバーの場合、GlassFishは、管理WebGUIツールまたはdomain.xml 直接。 domain.xml 次のようになります(XAデータソースを使用)。

    <jdbc-connection-pool datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"
                          name="jdbc_pool"
                          res-type="javax.sql.XADataSource">
    
      <property name="password" value="password"></property>
      <property name="databaseName" value="database_name"></property>
      <property name="serverName" value="localhost"></property>
      <property name="user" value="root"></property>
      <property name="portNumber" value="3306"></property>
      <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
      <property name="characterEncoding" value="UTF-8"></property>
      <property name="useUnicode" value="true"></property>
      <property name="characterSetResults" value="UTF-8"></property>
      <!-- The following two of our interest -->
      <property name="serverTimezone" value="UTC"></property>
      <property name="useLegacyDatetimeCode" value="false"></property>
    </jdbc-connection-pool>
    
    <jdbc-resource pool-name="jdbc_pool" 
                   description="description"
                   jndi-name="jdbc/pool">
    </jdbc-resource>
    

    WildFlyの場合、standalone-xx.yy.xmlで設定できます。 CLIコマンドを使用するか、管理Web GUIツールを使用します(XAデータソースを使用)。

    <xa-datasource jndi-name="java:jboss/datasources/datasource_name"
                   pool-name="pool_name"
                   enabled="true"
                   use-ccm="true">
    
        <xa-datasource-property name="DatabaseName">database_name</xa-datasource-property>
        <xa-datasource-property name="ServerName">localhost</xa-datasource-property>
        <xa-datasource-property name="PortNumber">3306</xa-datasource-property>
        <xa-datasource-property name="UseUnicode">true</xa-datasource-property>
        <xa-datasource-property name="CharacterEncoding">UTF-8</xa-datasource-property>
        <!-- The following two of our interest -->
        <xa-datasource-property name="UseLegacyDatetimeCode">false</xa-datasource-property>
        <xa-datasource-property name="ServerTimezone">UTC</xa-datasource-property>
    
        <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
        <driver>mysql</driver>
        <transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation>
    
        <xa-pool>
            <min-pool-size>5</min-pool-size>
            <max-pool-size>15</max-pool-size>
        </xa-pool>
    
        <security>
            <user-name>root</user-name>
            <password>password</password>
        </security>
    
        <validation>
            <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker"/>
            <background-validation>true</background-validation>
            <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter"/>
        </validation>
    
        <statement>
            <share-prepared-statements>true</share-prepared-statements>
        </statement>
    </xa-datasource>
    
    <drivers>
        <driver name="mysql" module="com.mysql">
            <driver-class>com.mysql.jdbc.Driver</driver-class>
        </driver>
    </drivers>
    

    同じことが非XAデータソースにも当てはまります。その場合、接続URL自体に直接追加できます。

    これらの言及されたすべてのプロパティは、JDBCドライバーで使用可能な言及されたクラス、つまりcom.mysql.jdbc.jdbc2.optional.MysqlXADataSourceに設定されます。 どちらの場合も、このクラスでそれぞれのセッターメソッドを使用します。

    たとえば、コアJDBC APIを直接使用する場合、またはTomcatで接続プールを使用する場合は、接続URL(context.xml内)に直接設定できます。 )

    <Context antiJARLocking="true" path="/path">
        <Resource name="jdbc/pool" 
                  auth="Container"
                  type="javax.sql.DataSource"
                  maxActive="100"
                  maxIdle="30"
                  maxWait="10000"
                  username="root"
                  password="password"
                  driverClassName="com.mysql.jdbc.Driver"
                  url="jdbc:mysql://localhost:3306/database_name?useEncoding=true&amp;characterEncoding=UTF-8&amp;useLegacyDatetimeCode=false&amp;serverTimezone=UTC"/>
    </Context>
    

    追加:

    ターゲットデータベースサーバーがDST対応ゾーンで実行されていて、夏時間(DST)がオフになっていない場合、問題が発生します。 UTCやGMTなどのDSTの影響を受けない標準のタイムゾーンを使用するようにデータベースサーバーを構成することをお勧めします。通常、UTCはGMTよりも優先されますが、どちらもこの点で類似しています。 このリンク

    ちなみに、JPA 2.1以降、EclipseLinkのプロプライエタリコンバータであるを削除しました。独自の標準コンバーターを提供します これは、必要に応じて、ほとんどまたはまったく変更することなく、別のJPAプロバイダーに移植できます。これで、java.util.Dateが次のようになります。 java.sql.Timestampにも置き換えられました 。

    import java.sql.Timestamp;
    import javax.persistence.AttributeConverter;
    import javax.persistence.Converter;
    import org.joda.time.DateTime;
    import org.joda.time.DateTimeZone;
    
    @Converter(autoApply = true)
    public final class JodaDateTimeConverter implements AttributeConverter<DateTime, Timestamp> {
    
        @Override
        public Timestamp convertToDatabaseColumn(DateTime dateTime) {
            return dateTime == null ? null : new Timestamp(dateTime.withZone(DateTimeZone.UTC).getMillis());
        }
    
        @Override
        public DateTime convertToEntityAttribute(Timestamp timestamp) {
            return timestamp == null ? null : new DateTime(timestamp, DateTimeZone.UTC);
        }
    }
    

    日付/時刻をエンドユーザーに表示または提示しながら、適切なユーザーのタイムゾーンに従って日付/時刻を変換するのは、関連するアプリケーションクライアント(サーブレット/ JSP / JSF /リモートデスクトップクライアントなど)の責任です。簡潔にするためにこの回答ではカバーされておらず、現在の質問の性質に基づいてトピックから外れています。

    一部のフィールドがオプションでない限り、コンバーターでのこれらのnullチェックも、関連するアプリケーションクライアントの責任であるため、必要ありません。

    今はすべてうまくいきます。その他の提案/推奨事項は大歓迎です。私の知らない人への批判は大歓迎です。



    1. SQLは、別のテーブルの別の列から1つの列を更新します

    2. PGTuneの代替-ClusterControlPostgreSQL構成

    3. `SqlDbType.Structured`を使用してNHibernateでテーブル値パラメーターを渡すことは可能ですか?

    4. mysql_fetch_arrayはすべての行を取得するわけではありません