2018年6月28日木曜日

PostgreSQL : テーブル一覧の取得方法

PostgreSQLにおけるテーブル一覧を取得するSQL。

select relname from pg_stat_user_tables

結果はこんな感じになる。

     relname
-----------------
reservable_room
meeting_room
usr
reservation

2018年6月26日火曜日

JPA : 複合主キー

JPAで複合主キーを定義する方法。その前に、まずJPAで単一主キーを定義する方法だが、これは@Idアノテーションを付加してやれば実現できる。

package example;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Class1 {
    @Id
    private String id;

    private String col1;

    // Getter/Setterは省略

}

問題は@Idアノテーションはひとつしか指定できないこと。とはいえ、実務上、複合主キーを指定したい場合というのが必ずある。こうした場合は、まず複合主キーを定義するクラスを用意する。@Embeddableというアノテーションを使用する。また、主キーの一意性を確保するためにequalsメソッドとhashCodeメソッドは必ず定義すること。

package example;

import javax.persistence.Embeddable;

@Embeddable
public class Key {

    private Integer id1;

    private Integer id2;

    // Getter/Setter、equals、hashCodeは省略

}

複合主キーを定義するクラスが出来たら、これを使ってEntityクラスを作成する。複合主キーフィールドに@EmbeddedIdを付加する。

package example;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;

@Entity
public class Class2 {
    @EmbeddedId
    private Key key;

    private String col1;

    // Getter/Setterは省略

}

これで複合主キーを指定するクラスの完成。単一主キーに比べて、ちょっと煩雑。

2018年6月16日土曜日

Spring : リクエストマッピング用のアノテーション

知らなかったのだが、Spring Frameworkのバージョン4.3以降だとRequestMapping以外にリクエストマッピング用のアノテーションが用意されている。

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
  • @PatchMapping

一目瞭然ではあるが、@GetMappingなら@RequestMapping(method = RequestMethod.GET)に対応しているし、@PostMappingには@RequestMapping(method = RequestMethod.POST)が対応しているといった具合である。だから、下記の2つのソースは同じように動作してくれる。

GetMapping使用
package hoge;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(path="/")
public class MainController {
    @GetMapping(path="/get")
    public @ResponseBody String get() {
        return "Hello World!";
    }
}

RequestMapping使用
package hoge;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(path="/")
public class MainController {
    @RequestMapping(method = RequestMethod.GET, path="/get")
    public @ResponseBody String get() {
        return "Hello World!";
    }
}

厳密には@GetMappingや@PostMappingは合成アノテーションなので、完全に動作が一致するわけではないかもしれない。実際に@GetMappingの中を覗いてみる。

@GetMapping
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {

    // 色々書かれているけど省略

}

@GetMappingに限らず、他の4つのアノテーションも同じような感じになっている。詳しくはもう少し調べてみないとよく分からない。けれど、これらのアノテーションを使うほうが可読性があがる気がするので積極的に使っていこうと思う。

2018年6月3日日曜日

Spring, JPA, Hibernate

Spring、JPA、Hibernateを使ってDBアクセスする簡単なアプリケーションを作成する。DBはPostgreSQLを使用する。

EclipseでSpring スターター・プロジェクトを選び、下記のようにテンプレートを選択する。


まず最初にapplication.propertiesの編集を行う。このファイルはsrc/main/resources配下に自動的に作成されている。開くと白紙の状態なので、以下のようにHibernateでPostgreSQLに接続するための設定を行う。

application.properties
spring.jpa.database=POSTGRESQL
spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:postgresql://localhost:5432/db_example
spring.datasource.username=postgres
spring.datasource.password=postgres

次にエンティティクラスを作成する。

User.java
package spring.jpa;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="usr")
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

このクラス定義に従って自動的にPostgreSQLにテーブルが作成される。

CRUDを行うクラスの作成。

UserRepository.java
package spring.jpa;

import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends CrudRepository<User, Long> {

}

分かりづらいのだがこのインターフェースを作成することで、自動的に単純なCRUDを行うクラスが生成される。

最後にControllerクラスの作成。

MainController.java
package spring.jpa;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(path="/")
public class MainController {
    @Autowired
    private UserRepository userRepository;

    @GetMapping(path="/add")
    public @ResponseBody String addNewUser(@RequestParam String name) {
        User u = new User();
        u.setName(name);
        userRepository.save(u);
        return "Saved";
    }

    @GetMapping(path="/all")
    public @ResponseBody Iterable<User> getAllUsers() {
        return userRepository.findAll();
    }
}

ここまで作成したらSpringアプリケーションを実行して、http://localhost:8080/add?name=ユーザー にアクセスしてみる。リクエストパラメータをきちんと設定する。


DBを確認すると、リクエストパラメータで指定したユーザーが作成されていることが分かる。

db_example=# select * from usr;
id |   name
----+----------
  1 | ユーザー
(1 行)

画面でも確認する。
http://localhost:8080/all

PostgreSQL : userテーブルは作成できない

PostgreSQLでは"user"という名称のテーブルを作成することが出来ない。Hibernate使用を前提として下記のようなEntityクラスを作成した。使用するDBは当然PostgreSQLである。

package entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 private Integer id;
 private String name;
 private String email;
 public Integer getId() {
  return id;
 }
 public void setId(Integer id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
}

これで、アプリケーションを実行すれば勝手に"user"というテーブルが出来上がるはずだと思い実行してみたのだが上手くいかない。コンソールを見るとエラーが出ていた。テーブル作成のところでエラーになっているようである。

そこで、@Tableアノテーションを追加してテーブル名を"usr"にしてやったら上手くいった。

package entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="usr")
public class User {
 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 private Integer id;
 private String name;
 private String email;
 public Integer getId() {
  return id;
 }
 public void setId(Integer id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
}