ファイル作成の順序
Spring Bootプロジェクトでのファイル作成の順序
Section titled “Spring Bootプロジェクトでのファイル作成の順序”Spring Bootアプリケーションを開発する際の、効率的なファイル作成の順序について解説します。
データベースアクセスの設計思想
Section titled “データベースアクセスの設計思想”Spring Bootでデータベースにアクセスする際には、主に2つの設計思想があります:
-
JPA(Java Persistence API): ORM(Object-Relational Mapping)の設計思想
- Hibernate: JPAの実装の一つ
- オブジェクトとリレーショナルデータベースを自動的にマッピング
- エンティティベースの開発
-
MyBatis: SQLマッパーフレームワーク
- SQLを直接制御しながら、Javaオブジェクトとデータベースの結果をマッピング
- SQLベースの開発
選択の指針:
- JPA(Hibernate): CRUD操作が中心、オブジェクト指向的な設計を重視、開発速度を優先
- MyBatis: 複雑なSQLクエリが多い、パフォーマンスが重要、既存のSQL資産を活用したい
基本的な開発フロー
Section titled “基本的な開発フロー”Spring Bootプロジェクトでは、下位レイヤーから上位レイヤーへ順番にファイルを作成するのが一般的です。
1. Model/Entity層 ↓2. Repository層 / Mapper層 ↓3. Service層 ↓4. Controller層 ↓5. DTO層 ↓6. Config層 ↓7. Exception層JPA(Hibernate)を使用する場合
Section titled “JPA(Hibernate)を使用する場合”1. Model/Entity層の作成
Section titled “1. Model/Entity層の作成”まず、データベースのテーブルに対応するエンティティクラスを作成します。
@Dataを使用した場合(推奨)
Section titled “@Dataを使用した場合(推奨)”@Dataアノテーションを使用すれば、コンストラクタ、getter/setterが自動生成されるため、定義不要です。
@Entity@Table(name = "users")@Data // getter/setter、toString、equals、hashCode、コンストラクタを自動生成@NoArgsConstructor // 引数なしコンストラクタ(JPAの要件)@AllArgsConstructor // 全フィールドを引数に持つコンストラクタ(オプション)public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@Column(nullable = false, length = 100) private String name;
@Column(unique = true, nullable = false, length = 255) @Email private String email;
@Column(nullable = false) private String password;
@CreatedDate @Column(nullable = false, updatable = false) private LocalDateTime createdAt;
@LastModifiedDate @Column(nullable = false) private LocalDateTime updatedAt;
// @Dataにより以下が自動生成される: // - 引数なしコンストラクタ(@NoArgsConstructor) // - 全フィールドを引数に持つコンストラクタ(@AllArgsConstructor) // - getter/setter // - toString() // - equals()/hashCode()}メリット:
- コードが簡潔で読みやすい
- ボイラープレートコードが削減される
- 保守性が向上する
⚠️ 重要な注意点: 双方向の関連がある場合の@Exclude
もしあなたが@Data(または@ToStringや@EqualsAndHashCode)を使い、かつ「双方向(親子両方から参照できる)」の関連を作るなら、手動で@Excludeを入れるのは必須の儀式だと思ってください。
問題のある例(無限ループが発生):
// Userエンティティ@Entity@Table(name = "users")@Data // ⚠️ 問題: 双方向の関連がある場合、無限ループが発生する可能性@NoArgsConstructorpublic class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
private String name;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL) private List<Order> orders = new ArrayList<>(); // ⚠️ OrderからもUserを参照}
// Orderエンティティ@Entity@Table(name = "orders")@Data // ⚠️ 問題: 双方向の関連がある場合、無限ループが発生する可能性@NoArgsConstructorpublic class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@ManyToOne @JoinColumn(name = "user_id") private User user; // ⚠️ UserからもOrderを参照(双方向)
private BigDecimal amount;}
// 問題: toString()やequals()/hashCode()が無限ループを引き起こす// User.toString() → Order.toString() → User.toString() → ...解決方法: @Excludeを使用
// Userエンティティ@Entity@Table(name = "users")@Data@NoArgsConstructor@ToString(exclude = "orders") // ✅ ordersフィールドをtoStringから除外@EqualsAndHashCode(exclude = "orders") // ✅ ordersフィールドをequals/hashCodeから除外public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
private String name;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL) private List<Order> orders = new ArrayList<>();}
// Orderエンティティ@Entity@Table(name = "orders")@Data@NoArgsConstructor@ToString(exclude = "user") // ✅ userフィールドをtoStringから除外@EqualsAndHashCode(exclude = "user") // ✅ userフィールドをequals/hashCodeから除外public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@ManyToOne @JoinColumn(name = "user_id") private User user;
private BigDecimal amount;}なぜ@Excludeが必須なのか:
- 無限ループの防止:
@ToStringが双方向の関連フィールドを含むと、循環参照によりスタックオーバーフローが発生 - パフォーマンスの問題:
@EqualsAndHashCodeが双方向の関連フィールドを含むと、計算コストが膨大になる - 予期しない動作: 双方向の関連を含む
equals()/hashCode()は、エンティティの管理状態によって予期しない動作を引き起こす可能性がある
ベストプラクティス:
- 双方向の関連フィールドは常に
@Excludeで除外する - IDフィールドのみを使用して
equals()/hashCode()を計算する(推奨)
// より安全な実装例@Entity@Table(name = "users")@Data@NoArgsConstructor@ToString(exclude = "orders")@EqualsAndHashCode(of = "id") // ✅ IDフィールドのみを使用public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
private String name;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL) private List<Order> orders = new ArrayList<>();}@Getter/@Setterを使用したほうが良いパターン
Section titled “@Getter/@Setterを使用したほうが良いパターン”以下の場合は、@Getter/@Setterを個別に使用することを推奨します:
- 特定のフィールドのみgetter/setterを生成したい場合
- setterを制限したい場合(例: idフィールドはsetterを生成しない)
- アクセス修飾子を制御したい場合
@Entity@Table(name = "users")@NoArgsConstructor // 引数なしコンストラクタ(JPAの要件)public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Getter // getterのみ生成(setterは生成しない) private Long id;
@Column(nullable = false, length = 100) @Getter @Setter private String name;
@Column(unique = true, nullable = false, length = 255) @Email @Getter @Setter private String email;
@Column(nullable = false) @Getter @Setter(AccessLevel.PRIVATE) // setterをprivateに制限(外部からの変更を防ぐ) private String password;
@CreatedDate @Column(nullable = false, updatable = false) @Getter // getterのみ生成(作成日時は外部から変更不可) private LocalDateTime createdAt;
@LastModifiedDate @Column(nullable = false) @Getter // getterのみ生成(更新日時は自動更新のため、外部から変更不可) private LocalDateTime updatedAt;
// コンストラクタ(必要に応じて) public User(String name, String email, String password) { this.name = name; this.email = email; this.password = password; }}使用例:
// idフィールドはgetterのみ(setterなし)User user = new User();user.getId(); // OK// user.setId(1L); // コンパイルエラー(setterが存在しない)
// passwordフィールドはprivate setter(クラス内からのみ変更可能)user.setPassword("newPassword"); // クラス内からのみアクセス可能
// createdAt/updatedAtはgetterのみ(外部から変更不可)user.getCreatedAt(); // OK// user.setCreatedAt(...); // コンパイルエラー(setterが存在しない)@Getter/@Setterを使うべき場合:
- IDフィールド: setterを生成しない(不変性を保証)
- 作成日時・更新日時: getterのみ生成(自動更新のため外部から変更不可)
- パスワードフィールド: setterをprivateに制限(セキュリティのため)
- 特定のフィールドのみアクセス制御: 細かい制御が必要な場合
作成する理由:
- データベースのスキーマを定義する
- 他のレイヤーの基盤となる
2. Repository層の作成
Section titled “2. Repository層の作成”次に、データアクセスを担当するリポジトリインターフェースを作成します。
@Repositorypublic interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByEmail(String email); boolean existsByEmail(String email); List<User> findByNameContaining(String name);}作成する理由:
- エンティティのCRUD操作を提供
- カスタムクエリを定義
3. DTO層の作成
Section titled “3. DTO層の作成”APIのリクエスト・レスポンス用のDTOクラスを作成します。
public class UserDTO { private Long id; private String name; private String email;
// コンストラクタ、getter/setter public UserDTO() {}
public UserDTO(Long id, String name, String email) { this.id = id; this.name = name; this.email = email; }
// getter/setter}
// src/main/java/com/example/myapp/dto/UserCreateRequest.javapublic class UserCreateRequest { @NotBlank(message = "Name is required") @Size(min = 1, max = 100) private String name;
@NotBlank(message = "Email is required") @Email(message = "Email must be valid") private String email;
@NotBlank(message = "Password is required") @Size(min = 8, message = "Password must be at least 8 characters") private String password;
// getter/setter}作成する理由:
- エンティティとAPIの分離
- バリデーションルールの定義
4. Service層の作成
Section titled “4. Service層の作成”ビジネスロジックを実装するサービスクラスを作成します。
@Service@Transactional(readOnly = true)public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) { this.userRepository = userRepository; }
public UserDTO findById(Long id) { User user = userRepository.findById(id) .orElseThrow(() -> new ResourceNotFoundException("User", id)); return convertToDTO(user); }
@Transactional public UserDTO create(UserCreateRequest request) { if (userRepository.existsByEmail(request.getEmail())) { throw new DuplicateResourceException("User", request.getEmail()); }
User user = new User(); user.setName(request.getName()); user.setEmail(request.getEmail()); user.setPassword(passwordEncoder.encode(request.getPassword()));
User savedUser = userRepository.save(user); return convertToDTO(savedUser); }
private UserDTO convertToDTO(User user) { return new UserDTO(user.getId(), user.getName(), user.getEmail()); }}作成する理由:
- ビジネスロジックの実装
- トランザクション管理
- エンティティとDTOの変換
5. Exception層の作成
Section titled “5. Exception層の作成”カスタム例外クラスを作成します。
public class ResourceNotFoundException extends RuntimeException { public ResourceNotFoundException(String resourceName, Object identifier) { super(String.format("%s with identifier %s not found", resourceName, identifier)); }}
// src/main/java/com/example/myapp/exception/DuplicateResourceException.javapublic class DuplicateResourceException extends RuntimeException { public DuplicateResourceException(String resourceName, Object identifier) { super(String.format("%s with identifier %s already exists", resourceName, identifier)); }}作成する理由:
- 統一された例外処理
- エラーメッセージの標準化
6. Controller層の作成
Section titled “6. Controller層の作成”最後に、HTTPリクエストを処理するコントローラークラスを作成します。
@RestController@RequestMapping("/api/users")public class UserController {
private final UserService userService;
public UserController(UserService userService) { this.userService = userService; }
@GetMapping("/{id}") public ResponseEntity<UserDTO> getUser(@PathVariable Long id) { UserDTO user = userService.findById(id); return ResponseEntity.ok(user); }
@PostMapping public ResponseEntity<UserDTO> createUser( @Valid @RequestBody UserCreateRequest request) { UserDTO createdUser = userService.create(request); return ResponseEntity.status(HttpStatus.CREATED).body(createdUser); }}作成する理由:
- HTTPリクエストの受け取り
- レスポンスの生成
7. Config層の作成(必要に応じて)
Section titled “7. Config層の作成(必要に応じて)”設定クラスを作成します。
@Configuration@EnableWebSecuritypublic class SecurityConfig { // セキュリティ設定}
// src/main/java/com/example/myapp/config/RestTemplateConfig.java@Configurationpublic class RestTemplateConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); }}実践的な開発順序の例
Section titled “実践的な開発順序の例”機能単位での開発
Section titled “機能単位での開発”1つの機能(例: ユーザー管理)を完全に実装してから、次の機能に進む方法です。
1. Userエンティティの作成2. UserRepositoryの作成3. UserDTO、UserCreateRequestの作成4. UserServiceの作成5. UserControllerの作成6. テストの作成7. 次の機能(例: Order管理)に進むレイヤー単位での開発
Section titled “レイヤー単位での開発”すべてのレイヤーを一度に作成する方法です。
1. すべてのエンティティを作成2. すべてのリポジトリを作成3. すべてのDTOを作成4. すべてのサービスを作成5. すべてのコントローラーを作成推奨される開発順序
Section titled “推奨される開発順序”小規模プロジェクト:
機能単位での開発を推奨→ 1つの機能を完全に実装してから次に進む中規模プロジェクト:
レイヤー単位での開発を推奨→ すべてのエンティティを作成してから、次のレイヤーに進む大規模プロジェクト:
モジュール単位での開発を推奨→ 1つのモジュール(例: ユーザー管理モジュール)を完全に実装してから次に進むファイル作成時のチェックリスト
Section titled “ファイル作成時のチェックリスト”各レイヤーのファイルを作成する際に確認すべき項目:
Entity作成時
Section titled “Entity作成時”-
@Entityアノテーションが付いているか -
@Idと@GeneratedValueが設定されているか - 適切な
@Column設定があるか -
@Dataまたは@Getter/@Setterが適切に設定されているか(Lombok使用時) -
@NoArgsConstructorが設定されているか(JPAの要件) - アクセス制御が必要なフィールドには
@Getter/@Setterを個別に使用しているか
Repository作成時
Section titled “Repository作成時”-
JpaRepositoryを継承しているか - 必要なカスタムクエリが定義されているか
- メソッド名が適切か
Service作成時
Section titled “Service作成時”-
@Serviceアノテーションが付いているか -
@Transactionalが適切に設定されているか - 例外処理が実装されているか
- DTOへの変換メソッドがあるか
Controller作成時
Section titled “Controller作成時”-
@RestControllerアノテーションが付いているか -
@RequestMappingが適切に設定されているか -
@Validアノテーションが使用されているか - 適切なHTTPステータスコードが返されているか
まとめ(JPA使用時)
Section titled “まとめ(JPA使用時)”JPA(Hibernate)を使用する場合のファイル作成の順序:
- Model/Entity層: データベーススキーマの定義
- Repository層: データアクセスの実装
- DTO層: APIのリクエスト・レスポンスの定義
- Service層: ビジネスロジックの実装
- Exception層: カスタム例外の定義
- Controller層: HTTPリクエストの処理
- Config層: 設定クラスの定義(必要に応じて)
この順序に従うことで、依存関係を明確にし、効率的に開発を進めることができます。
MyBatisを使用する場合(A5M2使用想定)
Section titled “MyBatisを使用する場合(A5M2使用想定)”MyBatisはSQLマッパーフレームワークで、SQLを直接制御しながらJavaオブジェクトとデータベースの結果をマッピングします。A5M2(MyBatis Generator)を使用することで、データベーススキーマからEntity、Mapperインターフェース、Mapper XMLファイルを自動生成できます。
基本的な開発フロー(MyBatis使用時)
Section titled “基本的な開発フロー(MyBatis使用時)”MyBatisを使用する場合の開発フローは、A5M2を使用してコードを自動生成することを前提とします。
1. データベーススキーマの作成 ↓2. A5M2によるコード自動生成 - Entityクラス - Mapperインターフェース - Mapper XMLファイル ↓3. DTO層の作成 ↓4. Service層の作成 ↓5. Controller層の作成 ↓6. Config層の作成(必要に応じて) ↓7. Exception層の作成(必要に応じて)1. データベーススキーマの作成
Section titled “1. データベーススキーマの作成”まず、データベーススキーマを作成します。
-- usersテーブルの作成CREATE TABLE users ( id BIGSERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);
-- ordersテーブルの作成CREATE TABLE orders ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL REFERENCES users(id), total_amount DECIMAL(10, 2) NOT NULL, order_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);2. A5M2によるコード自動生成
Section titled “2. A5M2によるコード自動生成”A5M2(MyBatis Generator)を使用して、データベーススキーマからコードを自動生成します。
A5M2の設定ファイル(generatorConfig.xml)
Section titled “A5M2の設定ファイル(generatorConfig.xml)”<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration> <context id="PostgreSQL" targetRuntime="MyBatis3">
<!-- コメント生成の無効化 --> <commentGenerator> <property name="suppressAllComments" value="true"/> </commentGenerator>
<!-- データベース接続情報 --> <jdbcConnection driverClass="org.postgresql.Driver" connectionURL="jdbc:postgresql://localhost:5432/mydb" userId="myuser" password="mypassword"> </jdbcConnection>
<!-- Java型の解決 --> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver>
<!-- Entityクラスの生成設定 --> <javaModelGenerator targetPackage="com.example.myapp.model" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaModelGenerator>
<!-- Mapper XMLファイルの生成設定 --> <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"> <property name="enableSubPackages" value="true"/> </sqlMapGenerator>
<!-- Mapperインターフェースの生成設定 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.example.myapp.mapper" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> </javaClientGenerator>
<!-- テーブルの設定 --> <table tableName="users" domainObjectName="User"> <property name="useActualColumnNames" value="false"/> <generatedKey column="id" sqlStatement="JDBC"/> </table>
<table tableName="orders" domainObjectName="Order"> <property name="useActualColumnNames" value="false"/> <generatedKey column="id" sqlStatement="JDBC"/> </table>
</context></generatorConfiguration>A5M2の実行
Section titled “A5M2の実行”A5M2を実行してコードを自動生成します。
# Mavenを使用する場合mvn mybatis-generator:generate
# または、A5M2プラグインを使用する場合# IntelliJ IDEAの場合: Databaseツールウィンドウから実行自動生成されるファイル
Section titled “自動生成されるファイル”A5M2により、以下のファイルが自動生成されます:
- Entityクラス(
src/main/java/com/example/myapp/model/User.javaなど) - Mapperインターフェース(
src/main/java/com/example/myapp/mapper/UserMapper.javaなど) - Mapper XMLファイル(
src/main/resources/mapper/UserMapper.xmlなど)
自動生成されるEntityクラスの例:
public class User { private Long id; private String name; private String email; private String password; private LocalDateTime createdAt; private LocalDateTime updatedAt;
// コンストラクタ、getter/setterが自動生成される // (A5M2の設定により、Lombokの@Dataを使用することも可能)}自動生成されるMapperインターフェースの例:
@Mapperpublic interface UserMapper { int deleteByPrimaryKey(Long id); int insert(User record); User selectByPrimaryKey(Long id); List<User> selectAll(); int updateByPrimaryKey(User record);}自動生成されるMapper XMLファイルの例:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.myapp.mapper.UserMapper"> <resultMap id="BaseResultMap" type="com.example.myapp.model.User"> <id column="id" property="id" jdbcType="BIGINT"/> <result column="name" property="name" jdbcType="VARCHAR"/> <result column="email" property="email" jdbcType="VARCHAR"/> <result column="password" property="password" jdbcType="VARCHAR"/> <result column="created_at" property="createdAt" jdbcType="TIMESTAMP"/> <result column="updated_at" property="updatedAt" jdbcType="TIMESTAMP"/> </resultMap>
<!-- 基本的なCRUD操作が自動生成される --></mapper>3. カスタムMapperメソッドの追加
Section titled “3. カスタムMapperメソッドの追加”自動生成されたMapperインターフェースとXMLファイルに、カスタムメソッドを追加します。
Mapperインターフェースにカスタムメソッドを追加:
@Mapperpublic interface UserMapper { // 自動生成されたメソッド int deleteByPrimaryKey(Long id); int insert(User record); User selectByPrimaryKey(Long id); List<User> selectAll(); int updateByPrimaryKey(User record);
// カスタムメソッドを追加 User selectByEmail(String email); boolean existsByEmail(String email); List<User> selectByNameContaining(String name);}Mapper XMLファイルにカスタムSQLを追加:
<mapper namespace="com.example.myapp.mapper.UserMapper"> <!-- 自動生成されたSQL -->
<!-- カスタムSQLを追加 --> <select id="selectByEmail" resultMap="BaseResultMap"> SELECT * FROM users WHERE email = #{email} </select>
<select id="existsByEmail" resultType="boolean"> SELECT EXISTS(SELECT 1 FROM users WHERE email = #{email}) </select>
<select id="selectByNameContaining" resultMap="BaseResultMap"> SELECT * FROM users WHERE name LIKE CONCAT('%', #{name}, '%') </select></mapper>4. DTO層の作成
Section titled “4. DTO層の作成”APIのリクエスト・レスポンス用のDTOクラスを作成します(JPA版と同じ)。
@Data@NoArgsConstructor@AllArgsConstructorpublic class UserDTO { private Long id; private String name; private String email;}
// src/main/java/com/example/myapp/dto/UserCreateRequest.java@Data@NoArgsConstructorpublic class UserCreateRequest { @NotBlank(message = "Name is required") @Size(min = 1, max = 100) private String name;
@NotBlank(message = "Email is required") @Email(message = "Email must be valid") private String email;
@NotBlank(message = "Password is required") @Size(min = 8, message = "Password must be at least 8 characters") private String password;}5. Service層の作成
Section titled “5. Service層の作成”ビジネスロジックを実装するサービスクラスを作成します。
@Service@Transactional(readOnly = true)@RequiredArgsConstructor@Slf4jpublic class UserService {
private final UserMapper userMapper; private final PasswordEncoder passwordEncoder;
public UserDTO findById(Long id) { User user = userMapper.selectByPrimaryKey(id); if (user == null) { throw new ResourceNotFoundException("User", id); } return convertToDTO(user); }
@Transactional public UserDTO create(UserCreateRequest request) { if (userMapper.existsByEmail(request.getEmail())) { throw new DuplicateResourceException("User", request.getEmail()); }
User user = new User(); user.setName(request.getName()); user.setEmail(request.getEmail()); user.setPassword(passwordEncoder.encode(request.getPassword()));
userMapper.insert(user); return convertToDTO(user); }
private UserDTO convertToDTO(User user) { return new UserDTO( user.getId(), user.getName(), user.getEmail() ); }}6. Controller層の作成
Section titled “6. Controller層の作成”HTTPリクエストを処理するコントローラークラスを作成します(JPA版と同じ)。
@RestController@RequestMapping("/api/users")@RequiredArgsConstructor@Slf4jpublic class UserController {
private final UserService userService;
@GetMapping("/{id}") public ResponseEntity<UserDTO> getUser(@PathVariable Long id) { UserDTO user = userService.findById(id); return ResponseEntity.ok(user); }
@PostMapping public ResponseEntity<UserDTO> createUser( @Valid @RequestBody UserCreateRequest request) { UserDTO createdUser = userService.create(request); return ResponseEntity.status(HttpStatus.CREATED).body(createdUser); }}ファイル作成時のチェックリスト(MyBatis使用時)
Section titled “ファイル作成時のチェックリスト(MyBatis使用時)”データベーススキーマ作成時
Section titled “データベーススキーマ作成時”- テーブル定義が適切か
- 主キーが設定されているか
- 外部キー制約が適切に設定されているか
- インデックスが適切に設定されているか
A5M2実行時
Section titled “A5M2実行時”- generatorConfig.xmlの設定が正しいか
- 生成されるパッケージ名が適切か
- 生成されるファイル名が適切か
Mapper作成時
Section titled “Mapper作成時”-
@Mapperアノテーションが付いているか - カスタムSQLが適切に記述されているか
- パラメータマッピングが適切か
- 結果マッピングが適切か
Service作成時
Section titled “Service作成時”-
@Serviceアノテーションが付いているか -
@Transactionalが適切に設定されているか - 例外処理が実装されているか
- DTOへの変換メソッドがあるか
まとめ(MyBatis使用時)
Section titled “まとめ(MyBatis使用時)”MyBatisを使用する場合のファイル作成の順序:
- データベーススキーマ: テーブル定義の作成
- A5M2によるコード自動生成: Entity、Mapperインターフェース、Mapper XMLファイル
- カスタムMapperメソッド: 必要なカスタムSQLの追加
- DTO層: APIのリクエスト・レスポンスの定義
- Service層: ビジネスロジックの実装
- Controller層: HTTPリクエストの処理
- Config層: 設定クラスの定義(必要に応じて)
- Exception層: カスタム例外の定義(必要に応じて)
JPAとMyBatisの使い分け:
- JPA(Hibernate): CRUD操作が中心、オブジェクト指向的な設計を重視、開発速度を優先
- MyBatis: 複雑なSQLクエリが多い、パフォーマンスが重要、既存のSQL資産を活用したい、A5M2によるコード自動生成を活用したい
この順序に従うことで、MyBatisを使用した開発を効率的に進めることができます。