docs/Spring全家桶/Spring/Spring中对于数据库的访问.md
Spring Դжַʽһһо٣
Spring Ӧò֧ JNDI WEB ϣ WebSphereJBossTomcat ȣͿʹ JNDI ȡԴ
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.2.xsd">
<!-- 1.ʹbeanjndiԴ -->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/orclight" />
</bean>
<!-- 2.ʹjeeǩjndiԴ1ȼۣҪռ -->
<jee:jndi-lookup id="dataSource" jndi-name=" java:comp/env/jdbc/orclight" />
</beans>
Spring ûṩݿӳصʵ֣Ҫѡʵݿӳءһʹ Druid (opens new window)Ϊݿӳصʾ
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- óʼСС -->
<property name="initialSize" value="1"/>
<property name="minIdle" value="1"/>
<property name="maxActive" value="10"/>
<!-- ûȡӵȴʱʱ -->
<property name="maxWait" value="10000"/>
<!-- üòŽһμ⣬ҪرյĿӣλǺ -->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!-- һڳСʱ䣬λǺ -->
<property name="minEvictableIdleTimeMillis" value="300000"/>
<property name="testWhileIdle" value="true"/>
<!-- ィΪTRUEֹȡӲ -->
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="false"/>
<!-- PSCacheָÿPSCacheĴС -->
<property name="poolPreparedStatements" value="true"/>
<property name="maxPoolPreparedStatementPerConnectionSize"
value="20"/>
<!-- ύʽĬϾTRUEԲ -->
<property name="defaultAutoCommit" value="true"/>
<!-- ֤ЧSQLͬòͬ -->
<property name="validationQuery" value="select 1 "/>
<property name="filters" value="stat"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
: 2022/11/16 20:10 / Ķ: 946668
ǰJDBCʱѾJavaʹJDBCӿڷʹϵݿʱҪ¼
DataSourceʵʾݿӳأDataSourceʵȡConnectionʵConnectionʵPreparedStatementʵResultSetȡģintȷдJDBCĹؼʹtry ... finallyͷԴ漰ĴҪȷύع
SpringʹJDBCͨIoCһDataSourceʵȻSpringṩһJdbcTemplateԷDzJDBCˣͨ£ǻʵһJdbcTemplate˼壬ҪʹTemplateģʽ
дʾ߲ԴʱǿƼʹHSQLDBݿ⣬һJavaдĹϵݿ⣬ڴģʽļģʽУֻһjardzʺʾ߲Դ롣
ʵʹΪȴMavenspring-data-jdbcȻ
AppConfigУҪ¼Bean
@Configuration
@ComponentScan
@PropertySource("jdbc.properties")
public class AppConfig {
@Value("${jdbc.url}")
String jdbcUrl;
@Value("${jdbc.username}")
String jdbcUsername;
@Value("${jdbc.password}")
String jdbcPassword;
@Bean
DataSource createDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(jdbcUrl);
config.setUsername(jdbcUsername);
config.setPassword(jdbcPassword);
config.addDataSourceProperty("autoCommit", "true");
config.addDataSourceProperty("connectionTimeout", "5");
config.addDataSourceProperty("idleTimeout", "60");
return new HikariDataSource(config);
}
@Bean
JdbcTemplate createJdbcTemplate(@Autowired DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
У
@PropertySource("jdbc.properties")ȡݿļ@Value("${jdbc.url}")עļãHikariDataSourceʱҪõעãDataSourceͨעġHSQLDBдһļjdbc.properties
# ݿļΪtestdb:
jdbc.url=jdbc:hsqldb:file:testdb
# HsqldbĬϵûsaǿַ:
jdbc.username=sa
jdbc.password=
ͨHSQLDBԴĹʼݿдһBeanSpringʱԶһusers
@Component
public class DatabaseInitializer {
@Autowired
JdbcTemplate jdbcTemplate;
@PostConstruct
public void init() {
jdbcTemplate.update("CREATE TABLE IF NOT EXISTS users (" //
+ "id BIGINT IDENTITY NOT NULL PRIMARY KEY, " //
+ "email VARCHAR(100) NOT NULL, " //
+ "password VARCHAR(100) NOT NULL, " //
+ "name VARCHAR(100) NOT NULL, " //
+ "UNIQUE (email))");
}
}
ڣϡֻҪҪݿBeanУעJdbcTemplateɣ
@Component
public class UserService {
@Autowired
JdbcTemplate jdbcTemplate;
...
}
SpringṩJdbcTemplateTemplateģʽṩһϵԻصΪصĹ߷ĿDZⷱtry...catch䡣
Ծʾ˵JdbcTemplate÷
ǿT execute(ConnectionCallback<T> action)ṩJdbcConnectionʹã
public User getUserById(long id) {
// עConnectionCallback:
return jdbcTemplate.execute((Connection conn) -> {
// ֱʹconnʵҪͷصJdbcTemplateԶͷ:
// ڲֶPreparedStatementResultSettry(...)ͷ:
try (var ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?")) {
ps.setObject(1, id);
try (var rs = ps.executeQuery()) {
if (rs.next()) {
return new User( // new User object:
rs.getLong("id"), // id
rs.getString("email"), // email
rs.getString("password"), // password
rs.getString("name")); // name
}
throw new RuntimeException("user not found by id.");
}
}
});
}
Ҳ˵صȡConnectionȻκλConnectionIJ
ٿT execute(String sql, PreparedStatementCallback<T> action)÷
public User getUserByName(String name) {
// ҪSQL䣬ԼPreparedStatementCallback:
return jdbcTemplate.execute("SELECT * FROM users WHERE name = ?", (PreparedStatement ps) -> {
// PreparedStatementʵѾJdbcTemplateڻصԶͷ:
ps.setObject(1, name);
try (var rs = ps.executeQuery()) {
if (rs.next()) {
return new User( // new User object:
rs.getLong("id"), // id
rs.getString("email"), // email
rs.getString("password"), // password
rs.getString("name")); // name
}
throw new RuntimeException("user not found by id.");
}
});
}
ǿT queryForObject(String sql, RowMapper<T> rowMapper, Object... args)
public User getUserByEmail(String email) {
// SQLRowMapperʵ:
return jdbcTemplate.queryForObject("SELECT * FROM users WHERE email = ?",
(ResultSet rs, int rowNum) -> {
// ResultSetĵǰӳΪһJavaBean:
return new User( // new User object:
rs.getLong("id"), // id
rs.getString("email"), // email
rs.getString("password"), // password
rs.getString("name")); // name
},
email);
}
queryForObject()УSQLԼSQLJdbcTemplateԶPreparedStatementԶִвѯResultSetṩRowMapperҪǰResultSetĵǰӳһJavaBeanءУʹConnection``PreparedStatement``ResultSetҪֶ
RowMapperһJavaBeanʵԷκJava磬ʹSELECT COUNT(*)ѯʱԷLong
public long getUsers() {
return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users", (ResultSet rs, int rowNum) -> {
// SELECT COUNT(*)ѯֻһУȡһ:
return rs.getLong(1);
});
}
ضм¼һУquery()
public List<User> getUsers(int pageIndex) {
int limit = 100;
int offset = limit * (pageIndex - 1);
return jdbcTemplate.query("SELECT * FROM users LIMIT ? OFFSET ?",
new BeanPropertyRowMapper<>(User.class),
limit, offset);
}
query()IJȻSQLSQLԼRowMapperʵֱʹSpringṩBeanPropertyRowMapperݿĽṹǡúJavaBeanһ£ôBeanPropertyRowMapperͿֱӰһм¼תΪJavaBean
ִеIJDzѯDz롢ºɾôҪʹupdate()
public void updateUser(User user) {
// SQLSQLظµ:
if (1 != jdbcTemplate.update("UPDATE users SET name = ? WHERE id = ?", user.getName(), user.getId())) {
throw new RuntimeException("User not found by id");
}
}
ֻһINSERTȽ⣬ǾijһУͨҪȡֵJdbcTemplateṩһKeyHolderһ
public User register(String email, String password, String name) {
// һKeyHolder:
KeyHolder holder = new GeneratedKeyHolder();
if (1 != jdbcTemplate.update(
// 1:PreparedStatementCreator
(conn) -> {
// PreparedStatementʱָRETURN_GENERATED_KEYS:
var ps = conn.prepareStatement("INSERT INTO users(email, password, name) VALUES(?, ?, ?)",
Statement.RETURN_GENERATED_KEYS);
ps.setObject(1, email);
ps.setObject(2, password);
ps.setObject(3, name);
return ps;
},
// 2:KeyHolder
holder)
) {
throw new RuntimeException("Insert failed.");
}
// KeyHolderлȡصֵ:
return new User(holder.getKey().longValue(), email, password, name);
}
JdbcTemplateطDzһһܡҪǿǣJdbcTemplateֻǶJDBCһװĿǾֶдtry(resource) {...}Ĵ룬ڲѯҪͨRowMapperʵJDBCJavaת
ܽһJdbcTemplate÷Ǿǣ
query()``queryForObject()ΪֻṩSQL䡢RowMapperupdate()ΪֻṩSQLͲexecute(ConnectionCallback)ʵ֣ΪõConnectionͿκJDBCʵʹȻǸֲѯƱṹʱܹJavaBeanһһӦôֱʹBeanPropertyRowMapperͺܷ㡣ṹJavaBeanһô죿ǾҪдһ²ѯʹĽṹJavaBeanһ¡
磬office_addressJavaBeanworkAddressҪָдѯ£
SELECT id, email, office_address AS workAddress, name FROM users WHERE email = ?
ʹJdbcTemplateʱõķList<T> query(String, RowMapper, Object...)``RowMapperþǰResultSetһм¼ӳΪJava Bean
ְѹϵݿı¼ӳΪJavaĹ̾ORMObject-Relational MappingORMȿѼ¼תJavaҲJavaתΪм¼
ʹJdbcTemplate``RowMapperԿԭʼORMҪʵָԶORMѡORMܣHibernate
SpringмHibernate
HibernateΪORMܣJdbcTemplateHibernateȻҪJDBCԣҪJDBCӳأԼHibernateMavenУǼ
AppConfigУȻҪDataSourceJDBCļԼʽ
@Configuration
@ComponentScan
@EnableTransactionManagement
@PropertySource("jdbc.properties")
public class AppConfig {
@Bean
DataSource createDataSource() {
...
}
}
ΪHibernateҪһLocalSessionFactoryBean
public class AppConfig {
@Bean
LocalSessionFactoryBean createSessionFactory(@Autowired DataSource dataSource) {
var props = new Properties();
props.setProperty("hibernate.hbm2ddl.auto", "update"); // Ҫʹ
props.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
props.setProperty("hibernate.show_sql", "true");
var sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
// ɨָpackageȡentity class:
sessionFactoryBean.setPackagesToScan("com.itranswarp.learnjava.entity");
sessionFactoryBean.setHibernateProperties(props);
return sessionFactoryBean;
}
}
עBeanнFactoryBean``LocalSessionFactoryBeanһFactoryBeanԶһSessionFactoryHibernateУSessionǷװһJDBC ConnectionʵSessionFactoryǷװJDBC DataSourceʵSessionFactoryӳأÿҪݿʱSessionFactoryһµSession൱ڴӳػȡһµConnection``SessionFactoryHibernateṩĵһLocalSessionFactoryBeanSpringṩΪǷ㴴SessionFactoryࡣ
ע洴LocalSessionFactoryBeanĴ룬PropertiesHibernateʼSessionFactoryʱõãõοHibernateĵֻ3ã
hibernate.hbm2ddl.auto=updateʾԶݿıṹעⲻҪãhibernate.dialect=org.hibernate.dialect.HSQLDialectָʾHibernateʹõݿHSQLDBHibernateʹһHQLIJѯ䣬SQLƣڡ롱SQLʱ趨ݿ⡰ԡݿŻSQLhibernate.show_sql=trueHibernateӡִеSQLڵԷdzãǿԷؿHibernateɵSQLǷǵԤڡDataSource``Properties֮⣬עsetPackagesToScan()ǴһpackageƣָʾHibernateɨJava࣬ԶҳӳΪݿ¼JavaBeanǻϸαдHibernateҪJavaBean
ţǻҪHibernateTransactionManager
public class AppConfig {
@Bean
PlatformTransactionManager createTxManager(@Autowired SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
}
HibernateTransactionManagerHibernateʹʽġΪֹеöϣνݿṹӳΪJava
µݿ
CREATE TABLE user
id BIGINT NOT NULL AUTO_INCREMENT,
email VARCHAR(100) NOT NULL,
password VARCHAR(100) NOT NULL,
name VARCHAR(100) NOT NULL,
createdAt BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
);
Уid``email``password``name``VARCHARͣemailΨһȷΨһԣcreatedAt洢͵ʱJavaBeanʾ£
public class User {
private Long id;
private String email;
private String password;
private String name;
private Long createdAt;
// getters and setters
...
}
ӳϵʮҪһЩעHibernateΰUserӳ䵽¼
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false, updatable = false)
public Long getId() { ... }
@Column(nullable = false, unique = true, length = 100)
public String getEmail() { ... }
@Column(nullable = false, length = 100)
public String getPassword() { ... }
@Column(nullable = false, length = 100)
public String getName() { ... }
@Column(nullable = false, updatable = false)
public Long getCreatedAt() { ... }
}
һJavaBeanӳ䣬Ǿͱһ@EntityĬ£ӳıuserʵʵıͬʵʱusersһ@Table(name="users")ʾ
@Entity
@Table(name="users)
public class User {
...
}
ÿԵݿеӳ@Column()ʶnullableָʾǷΪNULL``updatableָʾǷUPDATE䣬lengthָʾString͵еijȣûָĬ255
Ҫ@Idʶһ@GeneratedValueԱHibernateܶȡֵ
ϸĵͯЬܻעidͲlong``LongΪHibernateΪnullͲINSERTֵָǷݿɵֵHibernateΪǵijֵָINSERTֱгlongֶǾĬֵ0ˣÿβֵ0³һ붼ʧܡ
createdAtȻͣDzûʹlong``LongΪʹûͻᵼfindByExampleѯֻμǣΪӳʹõJavaBeanԶʹðװͶǻ͡
ʹHibernateʱҪʹû͵ԣʹðװͣLongInteger
ƵģٶһBookࣺ
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false, updatable = false)
public Long getId() { ... }
@Column(nullable = false, length = 100)
public String getTitle() { ... }
@Column(nullable = false, updatable = false)
public Long getCreatedAt() { ... }
}
ϸ۲User``BookᷢǶid``createdAtһģݿṹкܳÿͨǻͳһʹһɻƣcreatedAtʾʱ䣬updatedAtʾʱֶͨΡ
User``BookظЩֶͨΣǿᵽһУ
@MappedSuperclass
public abstract class AbstractEntity {
private Long id;
private Long createdAt;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false, updatable = false)
public Long getId() { ... }
@Column(nullable = false, updatable = false)
public Long getCreatedAt() { ... }
@Transient
public ZonedDateTime getCreatedDateTime() {
return Instant.ofEpochMilli(this.createdAt).atZone(ZoneId.systemDefault());
}
@PrePersist
public void preInsert() {
setCreatedAt(System.currentTimeMillis());
}
}
AbstractEntity˵Ҫעһ@MappedSuperclassʾڼ̳С⣬עǶһ@Transientһ⡱ԡΪgetCreatedDateTime()ǼóԣǴݿֵ˱Ҫע@TransientHibernate᳢ԴݿȡΪcreatedDateTimeڵֶδӶ
ע@PrePersistʶķʾǽһJavaBean־ûݿ֮ǰִINSERT䣩Hibernateִи÷ǾͿԶúcreatedAtԡ
AbstractEntityǾͿԴUser``Book
@Entity
public class User extends AbstractEntity {
@Column(nullable = false, unique = true, length = 100)
public String getEmail() { ... }
@Column(nullable = false, length = 100)
public String getPassword() { ... }
@Column(nullable = false, length = 100)
public String getName() { ... }
}
עʹõעjakarta.persistenceJPA淶һֻ֡ʹעķʽHibernateӳϵٽܴͳıȽϷXMLáͨSpringHibernateʱҲҪhibernate.cfg.xmlļһ仰ܽ
ʹSpringHibernateJPAע⣬κζXMLá
User``BookORMJava Bean֮ͨΪEntity Bean
userɾIJ顣ΪʹHibernateˣҪģʵǶUserJavaBeanСɾIJ顱DZдһUserServiceעSessionFactory
@Component
@Transactional
public class UserService {
@Autowired
SessionFactory sessionFactory;
}
Ҫ־ûһUserʵֻpersist()``register()Ϊ£
public User register(String email, String password, String name) {
// һUser:
User user = new User();
// úø:
user.setEmail(email);
user.setPassword(password);
user.setName(name);
// ҪidΪʹ
// 浽ݿ:
sessionFactory.getCurrentSession().persist(user);
// ѾԶid:
System.out.println(user.getId());
return user;
}
ɾһUser൱ڴӱɾӦļ¼עHibernateidɾ¼ˣҪȷUser``idԲɾ¼
public boolean deleteUser(Long id) {
User user = sessionFactory.getCurrentSession().byId(User.class).load(id);
if (user != null) {
sessionFactory.getCurrentSession().remove(user);
return true;
}
return false;
}
ͨɾ¼ʱһ÷ȸظü¼ɾע¼ʱload()``null
¼¼൱ȸUserָԣȻmerge()
public void updateUser(Long id, String name) {
User user = sessionFactory.getCurrentSession().byId(User.class).load(id);
user.setName(name);
sessionFactory.getCurrentSession().merge(user);
}
ǰڶUserʱеԱע@Column(updatable=false)Hibernateڸ¼¼ʱֻ@Column(updatable=true)Լ뵽UPDATEУṩһİȫԣСUser``email``createdAtԣִupdate()ʱ¶ӦݿСҲμǣHibernateṩģƹHibernateֱͨJDBCִUPDATEȻԸݿеֵ
DZдĴַǸָIJѯidѯǿֱӵload()Ҫʹѯ磬ִ²ѯ
SELECT * FROM user WHERE email = ? AND password = ?
ʹʲôѯ
һֳõIJѯֱӱдHibernateõHQLѯ
List<User> list = sessionFactory.getCurrentSession()
.createQuery("from User u where u.email = ?1 and u.password = ?2", User.class)
.setParameter(1, email).setParameter(2, password)
.list();
SQLȣHQLʹHibernateԶתΪʵʵıϸHQLԲοHibernateĵ
˿ֱӴHQLַ⣬HibernateʹһNamedQueryѯ֣ȻעСʹNamedQueryʱҪUserע
@NamedQueries(
@NamedQuery(
// ѯ:
name = "login",
// ѯ:
query = "SELECT u FROM User u WHERE u.email = :e AND u.password = :pwd"
)
)
@Entity
public class User extends AbstractEntity {
...
}
עNamedQuery``jakarta.persistence.NamedQueryֱӴHQLе㲻ͬǣռλʹ:e``:pwd
ʹNamedQueryֻҪѯͲ
public User login(String email, String password) {
List<User> list = sessionFactory.getCurrentSession()
.createNamedQuery("login", User.class) // NamedQuery
.setParameter("e", email) // e
.setParameter("pwd", password) // pwd
.list();
return list.isEmpty() ? null : list.get(0);
}
ֱдHQLʹNamedQueryӡǰ߿ڴֱ۵ؿѯ䣬߿Userͳһزѯ
һǽSpringмHibernateHibernateǵһ㷺ʹõORMܣǺܶС黹˵JPAJava Persistence APIɶ
JPA֮ǰҪעJavaEE1999ͷˣServletJMSƽ̨ͬJavaڷdzڱУҸѽӿڶˣȻԻؼҸɻȥʵֽӿڣûͿڲͬijṩIJƷѡлΪûдʱֻҪýӿڣҪþĵײʵ֣JDBC
JPAJavaEEһORMʵʵHibernateûɶ𣬵ûʹJPAôõľjakarta.persistenceorg.hibernateĵΪJPAֻǽӿڣԣҪѡһʵֲƷJDBCӿںMySQLһ
ʹJPAʱҲȫѡHibernateΪײʵ֣ҲѡJPAṩEclipseLinkSpringJPAļɣ֧ѡHibernateEclipseLinkΪʵ֡ȻHibernateΪJPAʵΪӣʾJPAĻ÷
ʹHibernateһֻҪ
ʵһڼHibernateȫһΪHibernateṩԼĽӿڣҲṩJPAӿڣJPAӿھ൱ͨJPAHibernate
ȻAppConfigʽDataSource
@Configuration
@ComponentScan
@EnableTransactionManagement
@PropertySource("jdbc.properties")
public class AppConfig {
@Bean
DataSource createDataSource() { ... }
}
ʹHibernateʱҪһLocalSessionFactoryBeanԶһSessionFactoryʹJPAҲƵģҲһLocalContainerEntityManagerFactoryBeanԶһEntityManagerFactory
@Bean
public LocalContainerEntityManagerFactoryBean createEntityManagerFactory(@Autowired DataSource dataSource) {
var emFactory = new LocalContainerEntityManagerFactoryBean();
// עDataSource:
emFactory.setDataSource(dataSource);
// ɨָpackageȡentity class:
emFactory.setPackagesToScan(AbstractEntity.class.getPackageName());
// ʹHibernateΪJPAʵ:
emFactory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
// :
var props = new Properties();
props.setProperty("hibernate.hbm2ddl.auto", "update"); // Ҫʹ
props.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
props.setProperty("hibernate.show_sql", "true");
emFactory.setJpaProperties(props);
return emFactory;
}
۲룬ҪעDataSource趨Զɨpackage⣬ҪָJPAṩ̣ʹSpringṩһHibernateJpaVendorAdapterHibernateԼҪãPropertiesʽע롣
ǻҪʵһJpaTransactionManagerʵʽ
@Bean
PlatformTransactionManager createTxManager(@Autowired EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
ǾJPAȫʼЩͯЬܴ֪JPAҪpersistence.xmlļԼӵorm.xmlļǸظߴңʹSpring+HibernateΪJPAʵ֣κļ
Entity BeanúһȫͬȫAnnotationעֻľҵͨJPAӿڲݿ⡣
UserServiceΪ˱ע@Component``@Transactional⣬ҪעһEntityManagerDzҪʹAutowired``@PersistenceContext
@Component
@Transactional
public class UserService {
@PersistenceContext
EntityManager em;
}
ǻعһJDBCHibernateJPAṩĽӿڣʵϣǵĹϵ£
| JDBC | Hibernate | JPA |
|---|---|---|
| DataSource | SessionFactory | EntityManagerFactory |
| Connection | Session | EntityManager |
SessionFactory``EntityManagerFactory൱DataSource``Session``EntityManager൱ConnectionÿҪݿʱҪȡµSession``EntityManagerٹرա
ǣעUserServiceעIJEntityManagerFactory``EntityManagerұע@PersistenceContextѵʹJPA̲߳ͬһEntityManager
ʵעIJEntityManagerһEntityManagerĴ࣬൱ڣ
public class EntityManagerProxy implements EntityManager {
private EntityManagerFactory emf;
}
Springע@PersistenceContext``EntityManagerԶעôڱҪʱԶEntityManager仰˵߳õEntityManagerȻͬһ࣬ôڲԲ̻ͬ߳ᴴͬEntityManagerʵ
ܽһ£ע@PersistenceContext``EntityManagerԱ̰߳ȫع
ˣUserServiceÿҵֱʹEntityManagerͺܷ㡣ѯΪ
public User getUserById(long id) {
User user = this.em.find(User.class, id);
if (user == null) {
throw new RuntimeException("User not found by id: " + id);
}
return user;
}
HQLѯƣJPAʹJPQLѯHQLࣺ
public User fetchUserByEmail(String email) {
// JPQLѯ:
TypedQuery<User> query = em.createQuery("SELECT u FROM User u WHERE u.email = :e", User.class);
query.setParameter("e", email);
List<User> list = query.getResultList();
if (list.isEmpty()) {
return null;
}
return list.get(0);
}
ͬģJPAҲ֧NamedQueryȸѯִٰ֣ѯ
public User login(String email, String password) {
TypedQuery<User> query = em.createNamedQuery("login", User.class);
query.setParameter("e", email);
query.setParameter("pwd", password);
List<User> list = query.getResultList();
return list.isEmpty() ? null : list.get(0);
}
NamedQueryͨעעUserϣĶһڵUserһ
@NamedQueries(
@NamedQuery(
name = "login",
query = "SELECT u FROM User u WHERE u.email=:e AND u.password=:pwd"
)
)
@Entity
public class User {
...
}
ݿɾĵIJԷֱʹpersist()``remove()``merge()ΪEntity Beanʹ÷dzﲻٶ
: 2022/11/16 21:07 / Ķ: 601258
ʹHibernateJPAݿʱORMɵҪǰResultSetÿһбJava Bean߰Java BeanԶתINSERTUPDATEIJУӶʵORM
ORM֪֮ΰӳ䵽Java BeanΪJava Beanϸ㹻עΪԪݣORMܻȡJava Beanע֪ν˫ӳ䡣
ôORMθJava BeanģԱupdate()и±Ҫԣ
ʹProxyģʽORMܶȡUserʵʵϲUser࣬Ǵ̳࣬User࣬ÿsetter˸д
public class UserProxy extends User {
boolean _isNameChanged;
public void setName(String name) {
super.setName(name);
_isNameChanged = true;
}
}
ԸٵÿԵı仯
һԶһϵʱֱͨgetterѯݿ⣺
public class UserProxy extends User {
Session _session;
boolean _isNameChanged;
public void setName(String name) {
super.setName(name);
_isNameChanged = true;
}
/**
* ȡUserAddress:
*/
public Address getAddress() {
Query q = _session.createQuery("from Address where userId = :userId");
q.setParameter("userId", this.getId());
List<Address> list = query.list();
return list.isEmpty() ? null : list(0);
}
}
ΪʵIJѯUserProxy뱣HibernateĵǰSessionǣύSessionԶرգʱٻȡgetAddress()ݿ⣬ȡIJһµݡˣORMAttached/Detached״̬ʾǰJava BeanSessionķΧڣSessionһ롱ܶѧȷ״̬仯߽磬ͻɴPersistentObjectException쳣ʽ״̬ʹͨJava Beanڱøӡ
⣬HibernateJPAΪʵּݶݿ⣬ʹHQLJPQLѯһתضݿSQLлݿ⣬һԶתܿ⣬SQLŻ鷳
ORMͨṩ˻棬һΪһͶ档һָһSessionΧڵĻ棬龰ǸѯʱβѯԷͬһʵ
User user1 = session.load(User.class, 123);
User user2 = session.load(User.class, 123);
ָSessionĻ棬һĬϹرգҪֶá漫ݵIJһԣԭSQLdzᵼĸ¡磺
// ߳1ȡ:
User user1 = session1.load(User.class, 123);
...
// һʱ߳2ȡ:
User user2 = session2.load(User.class, 123);
Чʱ̶߳ȡUserʵһģǣݿӦм¼ȫܱģ磺
-- û100:
UPDATE users SET bonus = bonus + 100 WHERE createdAt <= ?
ORMжid=123ûǷܸUPDATEӰ졣ǵݿֶ֧ͨӦóUPDATEִУORMܾ֪ˡ
ǰORM֮ܳΪȫԶORMܡ
ԱSpringṩJdbcTemplateORMȣҪм
JdbcTemplateȷԣÿζȡһݿǻ棬ִеSQLȫȷģȱǴȽϷINSERT INTO users VALUES (?,?,?)Ǹӡ
ԣȫԶORMHibernateдȫJdbcTemplate֮䣬һְԶORMֻResultSetԶӳ䵽Java BeanԶJava BeanԼдSQLMyBatisһְԶORMܡ
SpringмMyBatis
ȣҪMyBatisΣSpringûHibernateöMyBatisļɣԣҪMyBatisٷԼһSpringɵĿ⣺
ǰһȴDataSourceDZزٵģ
@Configuration
@ComponentScan
@EnableTransactionManagement
@PropertySource("jdbc.properties")
public class AppConfig {
@Bean
DataSource createDataSource() { ... }
}
ٻعһHibernateJPASessionFactory``EntityManagerFactoryMyBatis֮ӦSqlSessionFactory``SqlSession
| JDBC | Hibernate | JPA | MyBatis |
|---|---|---|---|
| DataSource | SessionFactory | EntityManagerFactory | SqlSessionFactory |
| Connection | Session | EntityManager | SqlSession |
ɼORM·ƵġʹMyBatisĺľǴSqlSessionFactoryҪSqlSessionFactoryBean
@Bean
SqlSessionFactoryBean createSqlSessionFactoryBean(@Autowired DataSource dataSource) {
var sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
ΪMyBatisֱʹSpringʽˣʹJDBCһģ
@Bean
PlatformTransactionManager createTxManager(@Autowired DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
HibernateͬǣMyBatisʹMapperʵӳ䣬MapperǽӿڡUserΪUser``users֮ӳUserMapperд£
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User getById(@Param("id") long id);
}
ע⣺MapperJdbcTemplate``RowMapperĸǶusersĽӿڷǶһUser getById(long)ѯҪӿڷҪȷдѯSQLע@SelectǡSQLκβ뷽ƶӦ磬idͨע@Param()ΪidSQLォ滻ռλ#{id}
жôÿֱSQLдӦռλɣ
@Select("SELECT * FROM users LIMIT #{offset}, #{maxResults}")
List<User> getAll(@Param("offset") int offset, @Param("maxResults") int maxResults);
ע⣺MyBatisִвѯݷķԶResultSetÿһתΪUserʵתȻǰӦͬķʽDZдSELECTı
-- created_timecreatedAt:
SELECT id, name, email, created_time AS createdAt FROM users
ִINSERT鷳㣬ΪϣUserʵˣķӿ@Insertע£
@Insert("INSERT INTO users (email, password, name, createdAt) VALUES (#{user.email}, #{user.password}, #{user.name}, #{user.createdAt})")
void insert(@Param("user") User user);
IJuserUser࣬SQLõʱ#{obj.property}ķʽдռλHibernateȫԶORMȣMyBatisдINSERT䡣
users``idôSQLвidϣȡҪټһ@Optionsע⣺
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
@Insert("INSERT INTO users (email, password, name, createdAt) VALUES (#{user.email}, #{user.password}, #{user.name}, #{user.createdAt})")
void insert(@Param("user") User user);
keyProperty``keyColumnֱָJavaBeanԺݿ
ִUPDATE``DELETEԱȽϼǶ巽£
@Update("UPDATE users SET name = #{user.name}, createdAt = #{user.createdAt} WHERE id = #{user.id}")
void update(@Param("user") User user);
@Delete("DELETE FROM users WHERE id = #{id}")
void deleteById(@Param("id") long id);
UserMapperӿڣҪӦʵִЩݿķȻԼдʵ࣬dz˱дUserMapperӿ⣬BookMapper``BonusMapperһһд̫鷳ˣMyBatisṩһMapperFactoryBeanԶMapperʵࡣһע
@MapperScan("com.itranswarp.learnjava.mapper")
...ע...
public class AppConfig {
...
}
@MapperScanͿMyBatisԶɨָMapperʵࡣҵУǿֱע룺
@Component
@Transactional
public class UserService {
// עUserMapper:
@Autowired
UserMapper userMapper;
public User getUserById(long id) {
// Mapper:
User user = userMapper.getById(id);
if (user == null) {
throw new RuntimeException("User not found by id.");
}
return user;
}
}
ɼҵҪͨXxxMapperݿⷽݿ⡣
SpringмMyBatisķʽֻҪõע⣬ûκXMLļMyBatisҲʹXMLӳϵSQL䣬磬Userʱֵ춯̬SQL
<update id="updateUser">
UPDATE users SET
<set>
<if test="user.name != null"> name = #{user.name} </if>
<if test="user.hobby != null"> hobby = #{user.hobby} </if>
<if test="user.summary != null"> summary = #{user.summary} </if>
</set>
WHERE id = #{user.id}
</update>
дXMLõŵǿװ̬SQLҰSQLһȱ̫÷ʱ鿴SQLҪλXMLСDzXML÷ʽҪ˽ͯЬĶٷĵ
ʹMyBatisSQLҪȫдŵִеSQLԼдSQLSQLŻdzҲԱд⸴ӵSQLʹݿضлݿܾͲ̫סϢǴĿûлݿȫijݿдŻSQL
https://www.w3cschool.cn/wkspring https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring https://dunwu.github.io/spring-tutorial https://mszlu.com/java/spring http://c.biancheng.net/spring/aop-module.html