2013年11月23日土曜日

org.hibernate.NonUniqueObjectExceptionにもちょっとハマった

Hibernateで以下の例外が出る場合は、リレーションシップにあるエンティティ(クラス)のhashCode、equalsメソッドがどう実装されているか見直しましょう。

Caused by: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:

jQueryの:notセレクタは何かと便利

HTMLのエレメントでclassに何種類か設定してある場合、jQueryの:notセレクタを使ってやると便利。

<div class="someA someB" />

<script>
  var divs = $('.someA:not(someB)');
</script>

みたいな感じ。

MySQLの作成日と更新日のカラム生成の設定が分かりやすかった記事

MySQLのテーブルでレコードの増減が頻繁に起こるテーブルは作成日と更新日のカラムを作成したりすると便利です。ただ、コードでいちいち書くの面倒くさいからデータベース側で設定できないか調べていると便利な記事を見つけました。

ポイントは、

  • Timestamp型はレコードに更新があれば自動更新してくれる。ただし、テーブルにつき1つ。
  • 作成日カラムはDatetime型にする。
  • レコードがINSERTされたら作成日を設定してやるトリガーを用意。
こんなとこでした。あとの注意点は作成日のデフォルト値かな。


http://www.marcus-povey.co.uk/2013/03/11/automatic-create-and-modified-timestamps-in-mysql/

HibernateのAutomatic State Detection

まだちょっとsaveOrUpdateとmergeの違いを分かっていないのですが、基本的なところでsaveする時とupdateする時の違いは、エンティティのID(主キー)がnullかどうかで自動制御しているようです。ちょっと、ここもハマった。

// in the first session
Cat cat = (Cat) firstSession.load(Cat.class, catID);

// in a higher tier of the application
Cat mate = new Cat();
cat.setMate(mate);

// later, in a new session
secondSession.saveOrUpdate(cat);   // update existing state (cat has a non-null id)
secondSession.saveOrUpdate(mate);  // save the new instance (mate has a null id)


http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html#objectstate-saveorupdate

HTMLのhiddenを使わずして値をエレメントに保持する

HTMLのページで、例えばテーブルの列のIDなどを保持したい場合にhiddenなどのタグを使うと面倒くさいので、エレメントその物にデータ(ID)を保持できるのが便利。

DIVのdata-value属性を使ってやると、jQueryだとdata()で取得できる。


<div class="comment" data-value="64">

 var value = $('[div selector]').data('value');

楽ちん楽ちん。

jQueryでAjaxを使ったDataTableでちょっとハマったとこ

jQueryのDatableのプラグインで、Ajaxを使ってサーバーサイドからデータを取るページを作るのに若干ハマったとこをメモ書き。

ページでテーブルが表示されてから、何かのアクションを起こしてテーブルをサーバーサイドのデータで再描画する時、sEchoというパラメータに注意。あまり注意してなかったので、適当に1と設定していたのですが、これは描画リクエストがある度に更新してやらないと、クライアントサイドで再描画が起こらない。(キャッシュしてるのかな?)

という事なので、バックエンドではインクリメントをして返してやると、ちゃんとテーブルを描画してくれました。

stringsEchoAn unaltered copy of sEcho sent from the client side. This parameter will change with each draw (it is basically a draw count) - so it is important that this is implemented. Note that it strongly recommended for security reasons that you 'cast' this parameter to an integer in order to prevent Cross Site Scripting (XSS) attacks.

2013年11月21日木曜日

JPAとHibernateのCascadeTypeにハマりました。。。


Hibernateでエンティティの関連性にCascadeTypeを使うと、データ取得だけとか、更新もするとか、いろいろ指定できるはずなのですが、できない??結構ハマったのですが、いろいろと調べると参考になるサイトに、JPAとHibernateでそれぞれCascadeTypeのアノテーションがあり、HibernateのSessionを使っているとJPAのCascadeTypeでは予測した挙動で動いてくれないようです。これはハマる!!

org.hibernate.annotations.CascadeType
javax.persistence.CascadeType
は違う!!

JPA
 @OneToMany(fetch = FetchType.LAZY, 
       cascade = {CascadeType.PERSIST,CascadeType.MERGE }, 
       mappedBy = "stock")
Hibernate
@OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
@Cascade({CascadeType.SAVE_UPDATE})

それにしても、@OneToManyはjavax.persistenceで、@Cascadeはorg.hibernate.annotations、ややこしい。。。

http://docs.jboss.org/hibernate/core/3.5/javadocs/org/hibernate/annotations/CascadeType.html
http://docs.oracle.com/javaee/6/api/javax/persistence/CascadeType.html

SpringのControllerでリクエストパラメーターが多い時はMultiValueMapを使う

SpringのControllerでリクエストパラメーターをたくさん受け取る場合、org.springframework.util.MultiValueMapを使うと便利。

パラメーター(キー)がユニークな場合は、MultiValueMap<String,String>なんでgetFirst(K key)で、パラメーター(キー)に紐付けられた値が複数ある場合は、MultiValueMap<String,List<String>>をget(Object key)で取れる。

http://docs.spring.io/spring/docs/3.1.4.RELEASE/javadoc-api/org/springframework/util/MultiValueMap.html
http://stackoverflow.com/questions/16355168/spring-mvc-requestparam-as-map-get-url-array-parameters-not-working

2013年11月16日土曜日

HTMLのformをjQueryでsubmitさせない方法

<form id="someform">....</form>

<script>
  $('#someform').submit(function(event){
      event.preventDefault();
  });
</script>

event.preventDefault()はイベント制御には何かと便利。

http://api.jquery.com/event.preventDefault/


jQueryとAjaxを使ってフォームのデータを送信する時、たくさんのエレメントがあると面倒くさいのでserialize()を使う。

<form id="someForm">...</form>

<script>
  $.ajax({
      url: 'someurl',
      type: 'post',
      data: $('#someForm').serialize()
  }) ;
</script>

こんな感じ。

http://stackoverflow.com/questions/5004233/capture-all-of-the-forms-data-and-submit-it-to-a-php-script-jquery-ajax-post

JUnit4で特定のテストケースを実行しない方法

これは非常に簡単で@Testで指定したテストケースを@Ignoreで無視しておいてと教えてあげればいい。

http://junit.sourceforge.net/javadoc/org/junit/Ignore.html

HibernateのsaveOrUpdateについて

テーブルにレコードを追加、もしくは既にあるレコードを更新する場合にSessionのsaveOrUpdateを使っているのだが、INSERTかUPDATEかの挙動はプライマリーキーがテーブルに存在しているかどうかで決定されるようだ。nullであればもちろん追加される。

しかしながら、updateやsaveOrUpdateやmergeなどがあって、まだまだ違いが不明。ここは要する調査。

MySQLのselect文で連番を自動生成する方法

変数を使ってインクリメントするだけ。

mysql> set @n=0;
mysql> select @n:=@n+1 serial_number from table1;

http://stackoverflow.com/questions/15930514/mysql-auto-increment-temporary-column-in-select-statement

MySQLのselectからinsertする構文

insert into table1
select a, b, c from table2 where id=?

みたいな感じ。

http://stackoverflow.com/questions/15523597/mysql-insert-into-values-and-select

HTMLのformのエレメントを一括で無効化する方法

<fieldset></fieldset>でdisabled属性を使えば良い。

<form>
  <fieldset>
    <legend>Personalia:</legend>
    Name: <input type="text"><br>
    Email: <input type="text"><br>
    Date of birth: <input type="text">
  </fieldset>
</form>

http://www.w3schools.com/tags/tag_fieldset.asp

2013年11月15日金曜日

MySQLで外部キー制約を一時的に解除する方法

MySQLで外部キー制約を持ったテーブルの定義を変更したい場合、何かと制約でエラーが出て変更できない面倒くさい状況が出るので回避策。

> SET foreign_key_checks=0 ------> 外部キー制約を解除
> SET foreign_key_checks=1 ------> 外部キー制約を有効

http://stackoverflow.com/questions/2300396/force-drop-mysql-bypassing-foreign-key-constraint

OS Xのターミナルでカーソルを先頭、最後尾に戻すショートカット

ctrl + a -----> front
ctrl + e -----> end

http://apple.stackexchange.com/questions/8928/move-to-start-of-line-in-terminal-app

2013年11月8日金曜日

HibernateでLocalSessionFactoryBeanを複数設定した場合の使いわけ

Hibernateで複数のデータベースに接続したい場合、LocalSessionFactoryBeanを複数設定ファイルに書きますが、ソースコードのDAO側でどうやって切り分けるのかが分からない。


    <bean id="sessionFactoryA" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>/WEB-INF/A.cfg.xml</value>
        </property>
    </bean>

   <bean id="sessionFactoryB" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>/WEB-INF/B.cfg.xml</value>
        </property>

    </bean>

調べてみると、意外にも簡単で@Qualifierアノテーションでidを指定するだけでOK。

@Repository
public class SomeDaoImpl implements SomeDao
{
    @Autowired
    @Qualifier(value="sessionFactoryA")
    private SessionFactory _sessionFactory;


こんな感じ。簡単簡単。

2013年11月7日木曜日

とりあえずHibernateのエンティティマッピングの書き方をすぐ忘れてしまうので。。。

とりあえずHibernateのエンティティマッピングの書き方をすぐ忘れてしまうので、一番すっきりとしていて分かりやすいお手本のリンクをメモっておくことにした。

http://en.wikibooks.org/wiki/Java_Persistence/OneToOne

Hibernateでカラムのソートの昇順・降順を指定するには@OrderByを使う

@OrderColumnの落とし穴 でHibernateのエンティティで一対多の関係を持ったコレクションのフィールドで@OrderColumnを使用した場合に、java.util.Listがnullオブジェクトを追加してしまうのでjava.util.Setを使う事にしました。

じゃあそのコレクションのソート降順・昇順の指定はどうなるんだ?という事ですが、@OrderByで指定できるようです。中身は@OrderBy("ID ASC")もしくは@OrderBy("ID DESC")のように、ここはシンプルに指定できます。また、なぜか@OrderColumnは指定する必要が無い事に気づきました。なんで???

またもやHibernateの未知なブラックボックスです。どうやって@OrderByと@OrderColumnを使い分けるのだろう??

http://stackoverflow.com/questions/11433195/hibernate-orderby-vs-ordercolumn-to-maintain-the-order-of-a-collection

2013年11月6日水曜日

とりあえずSpring+Hibernateで、DAO(データレイヤー)をJUnit4でテストする上で分かったことをまとめた。

まだ謎が多いので、分かった事をとりあえず一覧で。


  • JUnit4で作ったクラスはAbstractTransactionalJUnit4SpringContextTestsを継承する。なぜ?
  • spring-test.jarをpom.xmlに追加
  • @RunWith(SpringJUnit4ClassRunner.class)をクラスレベルで書く。なぜ必要?
  • @ContextConfiguration(locations={classpath:applicationContext.xml, classpath:hibernate.cfg.xml})をクラスレベルで書いて、設定ファイルを読み込む。この設定ファイルはクラスパスがとおった
  • @TransactionConfiguratioをクラスレベルで書いて、defaultRollback=trueにする。ロールバック機能を使うと、データベースの状態をテスト前の状態にできるから便利。
  • public void setDataSource(DataSource dataSource)をオーバーライドする。@Resource(name="dataSource")で設定ファイルで指定されているdataSourceを指定。
とにかくハマったとこ。。。

  1. Maven+Eclipse+WTPのファイル構造で設定ファイルをsrc/main/webapp/WEB-INF/は、クラスパス上にはならないので、src/test/resourceにテスト用の設定ファイルをtest-applicationContext.xml, test-hibernate.cfg.xmlのようにコピーした。もっと賢いやり方ないのかな。。。?ただ、WEB-INFから設定ファイルは動かしたくない。
  2. setDataSourceでtest-hibernate.cfg.xmlからDBのコネクション情報を指定してあげないといけないのだが、<session-factory></session-factory>の中に一括して書いてあるので、コネクション上に関してだけ抜き出して、applicationContext.xmlでdataSourceとして書きだした。
多くに共通してるとこは、設定の仕方が多い事が仇になっているということ。それがSpringとかHibernateの分かりにくいとこなのかなと実感。


参考にしたサイト:

http://stackoverflow.com/questions/2377763/abstracttransactionaljunit4springcontexttests-cant-get-the-dao-to-find-inserte
http://zakato.sblo.jp/article/50155918.html
http://java-cauldron.blogspot.com/2012/07/writing-junit4-tests-spring-30.html
http://mvnrepository.com/artifact/org.springframework/spring-test/3.2.4.RELEASE
http://kinoushi.blogspot.com/2008/08/abstracttransactionaljunit4springcontex.html
http://stackoverflow.com/questions/17220432/failed-to-load-applicationcontext-for-junit-test-of-spring-controller
http://junit.sourceforge.net/javadoc/org/junit/Assert.html
http://intink.blogspot.com/2012/12/hibernate4spring-framework3.html
http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/testing.html#testcontext-fixture-di
http://forum.spring.io/forum/spring-projects/container/38874-transactional-junit4-controller-testing-with-multiple-datasources
http://forum.spring.io/forum/spring-projects/container/49585-how-to-get-contextconfiguration-using-web-inf-applicationcontext-xml
http://forum.spring.io/forum/spring-projects/web/97105-testing-problem-junit4-7-spring3-0-5-hibernate-3-3-2



@OrderColumnの落とし穴

@OrderColumnにハマった。。。Stackoverflowで書いてある状況と全く同じで、一対多の関連性のあるエンティティで多の方のエンティティにListを使っていると、何故かデータベースのテーブルに無いレコードがNullとしてListに入っている。????ここにハマった。

要するにListと使って多エンティティを保持すると、保持される順序を指定しないといけないので@OrderColumnを使うのだが、ここの仕様がややこしくてブラックボックス。

The order column must be of integral type. The persistence provider maintains a contiguous (non-sparse) ordering of the values of the order column when updating the association or element collection. The order column value for the first element is 0.
※contiguous=切れ目の無い

と、JavaDocを読んでててイマイチ不明なのだが、要するに@OrderColumnで指定するカラムがintの主キーで、400が一番若いIDだとすると、0~399まではテーブルには存在しないのだが、わざわざご丁寧に0~399までをnullオブジェクトとしてListの保存するわけだ。これが、contiguous (non-sparse) ordering. なんとお節介な機能だ。。。

そして、これを回避するにはList型でなくSet型を使って使うとnullオブジェクトが保持されなくなったのだが、どうもここはまだまだ奥が深そう。。。こういうところがHibernateの分かりにくいところ。。。

http://stackoverflow.com/questions/13307849/hibernate-returns-list-with-null-values-onetomany-annotation-with-list-type
http://docs.oracle.com/javaee/6/api/javax/persistence/OrderColumn.html

HibernateのFetchTypeがLAZYとEAGERの違い


2つのエンティティ(テーブル)が一対多の関連性を持つ場合、どのタイミングで多のエンティティをロードしてあげるか、FetchTypeで2通りのやり方がある。

@OneToMany(fetch=FetchType.EAGER)
@OneToMany(fetch=FetchType.LAZY)

例えば、大学(Univeristy)というエンティティと学生(Student)というエンティティが一対多で関連付けられているとすると、Listのstudentsにデータをロードするタイミングとして、他のフィールド(id, name, address)と同じタイミングでロードするEAGERと、getStudents()などのオンディマンドでゲッターを呼ぶ場合にロードするLAZYのやり方がある。

public class University {
 private String id;
 private String name;
 private String address;
 private List<Student> students;

 // setters and getters
}

使い分けるポイントとしては、studentsにどれだけのデータがロードされるか、一度に全てロードする事が得策かどうかを考える必要がある。

http://stackoverflow.com/questions/2990799/difference-between-fetchtype-lazy-and-eager-in-java-persistence