關注點
- 使用 JPA 連接 MySql,連通創建資料。
使用 JPA 連接 MySql
加入相關依賴
以下是我們需要在 pom.xml 中加入的相關依賴:
- logback-classic:提供高效能與靈活的日誌記錄功能,為 SLF4J (Simple Logging Facade for Java) 的標準實作。
- hibernate-core:提供 Java 物件與關聯式資料庫之間的映射和管理功能(ORM)。它支援 JPA 規範,包含快取、事務管理與查詢語言等功能。
spring-orm和spring-data-jpa皆可透過 Hibernate 作為底層實作。 - mysql-connector-j:MySQL 的 JDBC 驅動程式,允許 Java 應用程式與 MySQL 資料庫進行連線與互動。
- HikariCP:高效能的 JDBC 連線池實作,提供優異的連線管理與效能最佳化。
- spring-orm:Spring 框架的一部分,提供對 ORM 框架的整合支援,結合 Spring 的依賴注入與事務管理功能。
- spring-data-jpa:Spring 提供用來簡化 JPA 使用的抽象層,具備自動生成查詢方法、分頁與排序等功能,大幅降低資料庫互動的開發成本。
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.32</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>7.2.5.Final</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.6.0</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>7.0.5</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>4.0.3</version>
</dependency>
設定資料庫連線
資料庫連線資訊通常統一設定在 application.properties 中。
以下是相關的參數定義:
JDBC 與 DataSource 設定
- spring.datasource.url:資料庫的連接 URL,格式為 jdbc:mysql://hostname:port/databaseName?param1=value1¶m2=value2。
- spring.datasource.username:資料庫的使用者名稱。
- spring.datasource.password:資料庫的密碼。
- spring.datasource.driver-class-name:JDBC 驅動程式的類名,對於 MySQL 是 com.mysql.cj.jdbc.Driver。
Hibernate 與 JPA 設定
- spring.jpa.hibernate.ddl-auto:Hibernate 的 DDL (Data Definition Language) 自動生成策略。設為 update 代表會根據 Entity 自動更新資料庫結構。
- spring.jpa.show-sql:設為 true 時,會在控制台印出 Hibernate 實際執行的 SQL 語句,方便 Debug。
spring.datasource.url=jdbc:mysql://localhost:3306/dev?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=account
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
讀取資料庫連線資訊與設定 Spring 容器
在純 Spring 環境下讀取外部屬性檔案有幾種常見做法:
Environment 物件:透過注入 Spring 的 Environment 物件,使用 getProperty 方法讀取參數值。
@Value 註解:直接在屬性上標記並讀取 application.properties 中的值。
@ConfigurationProperties:將屬性綁定到特定的 Java 類別中(較常用於 Spring Boot)。
此處我們採用 Environment 物件 的方式設定基礎建設。
Environment 允許從 application.properties 讀取屬性,也支援系統環境變數等來源。
以下是相關程式碼:
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import jakarta.persistence.EntityManagerFactory;
@Configuration
@PropertySource("classpath:application.properties")
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "sparrow.repository")
public class JPAMySqlConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Autowired
private Environment env;
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(env.getProperty("spring.datasource.url"));
config.setUsername(env.getProperty("spring.datasource.username"));
config.setPassword(env.getProperty("spring.datasource.password"));
return new HikariDataSource(config);
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("sparrow.entity");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
factoryBean.setJpaVendorAdapter(vendorAdapter);
Properties props = new Properties();
props.put("hibernate.show_sql", env.getProperty("spring.jpa.show-sql"));
props.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
props.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
factoryBean.setJpaProperties(props); // 設定 Hibernate 的相關屬性,顯示 SQL、DDL 自動生成策略和方言等
return factoryBean;
}
@Bean
public PlatformTransactionManager transactionManager(
EntityManagerFactory emf) {
if (emf != null) {
return new JpaTransactionManager(emf);
}
throw new IllegalArgumentException("EntityManagerFactory cannot be null");
}
}
新增一個使用者
Entity 類別實作
Entity 是記憶體中的 Java 類別,透過 JPA 註解與資料庫中的資料表進行映射綁定。
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 50)
private String name;
@Column(nullable = false, length = 50)
private String password;
@Column(nullable = false, length = 50)
private String email;
@Column(columnDefinition = "TEXT")
private String description;
// 必須提供無參數的建構子,JPA 需要使用反射來創建實體對象
public User() {
}
// getter 和 setter 方法,用於訪問和修改實體在記憶體中的屬性
// ... 省略 getter 和 setter 方法 ...
}
Repository 類別實作
宣告 Repository 介面並繼承 JpaRepository。
Spring Data JPA 會在執行時期自動提供其實作類別,開發者無須手動撰寫基礎的 CRUD 邏輯。
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import sparrow.entity.User;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 預設已繼承標準的 CRUD 方法
// 若有複雜查詢需求,可依照 Spring Data 命名規範自訂方法名稱
}
實際運作
這是一個將 Entity 寫入資料庫的簡單範例。
GenericApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
try {
UserRepository userRepository = context.getBean(UserRepository.class);
System.out.println("正在執行...");
User newUser = new User();
newUser.setPassword("password");
newUser.setName("Tester");
newUser.setEmail("[email protected]");
newUser.setDescription("這是一個測試使用者");
userRepository.save(newUser);
System.out.println("使用者已儲存,ID 為: " + newUser.getId());
List<User> users = userRepository.findAll();
System.out.println("目前資料庫中的使用者總數: " + users.size());
users.forEach(u -> System.out.println(" - " + u.getName() + " (" + u.getEmail() + ")"));
} catch (Exception e) {
System.err.println("發生錯誤:");
e.printStackTrace();
} finally {
System.out.println("關閉 Spring 容器...");
context.close();
}
