Back to Javatutorial

Spring中对于数据库的访问

docs/Spring全家桶/Spring/Spring中对于数据库的访问.md

1.0.031.7 KB
Original Source

Դ

Spring Դ

Spring Դжַʽһһо٣

#ʹ JNDI Դ

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>

# JDBC Դ

<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>

ʹJDBC

: 2022/11/16 20:10 / Ķ: 946668


ǰJDBCʱѾJavaʹJDBCӿڷʹϵݿʱҪ¼

  • ȫDataSourceʵʾݿӳأ
  • Ҫдݿķڲ²ݿ⣺
    • ȫDataSourceʵȡConnectionʵ
    • ͨConnectionʵPreparedStatementʵ
    • ִSQL䣬DzѯͨResultSetȡ޸ģint

ȷдJDBCĹؼʹtry ... finallyͷԴ漰ĴҪȷύع

SpringʹJDBCͨIoCһDataSourceʵȻSpringṩһJdbcTemplateԷDzJDBCˣͨ£ǻʵһJdbcTemplate˼壬ҪʹTemplateģʽ

дʾ߲ԴʱǿƼʹHSQLDBݿ⣬һJavaдĹϵݿ⣬ڴģʽļģʽУֻһjardzʺʾ߲Դ롣

ʵʹΪȴMavenspring-data-jdbcȻ

  • org.springframework:spring-context:6.0.0
  • org.springframework:spring-jdbc:6.0.0
  • jakarta.annotation:jakarta.annotation-api:2.1.1
  • com.zaxxer:HikariCP:5.0.1
  • org.hsqldb:hsqldb:2.7.1

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);
    }
}

У

  1. ͨ@PropertySource("jdbc.properties")ȡݿļ
  2. ͨ@Value("${jdbc.url}")עļã
  3. һDataSourceʵʵHikariDataSourceʱҪõעã
  4. һJdbcTemplateʵҪע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;
    ...
}

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ԶִвѯResultSetRowMapperҪǰ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䡢RowMapper
  • Ը²ѡupdate()ΪֻṩSQLͲ
  • κθӵIJҲͨ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УǼ

  • org.springframework:spring-context:6.0.0
  • org.springframework:spring-orm:6.0.0
  • jakarta.annotation:jakarta.annotation-api:2.1.1
  • jakarta.persistence:jakarta.persistence-api:3.1.0
  • org.hibernate:hibernate-core:6.1.4.Final
  • com.zaxxer:HikariCP:5.0.1
  • org.hsqldb:hsqldb:2.7.1

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ʱ趨ݿ⡰ԡݿŻSQL
  • hibernate.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ָʾǷUPDATElengthָʾ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;
}

Insert

Ҫ־ûһ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;
}

Delete

ɾһ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

Update

¼¼൱ȸ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 = ?

ʹʲôѯ

ʹHQLѯ

һֳõ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.persistence׼org.hibernateĵΪJPAֻǽӿڣԣҪѡһʵֲƷJDBCӿںMySQLһ

ʹJPAʱҲȫѡHibernateΪײʵ֣ҲѡJPAṩEclipseLinkSpringJPAļɣ֧ѡHibernateEclipseLinkΪʵ֡ȻHibernateΪJPAʵΪӣʾJPAĻ÷

ʹHibernateһֻҪ

  • org.springframework:spring-context:6.0.0
  • org.springframework:spring-orm:6.0.0
  • jakarta.annotation:jakarta.annotation-api:2.1.1
  • jakarta.persistence:jakarta.persistence-api:3.1.0
  • org.hibernate:hibernate-core:6.1.4.Final
  • com.zaxxer:HikariCP:5.0.1
  • org.hsqldb:hsqldb:2.7.1

ʵһڼ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ṩĽӿڣʵϣǵĹϵ£

JDBCHibernateJPA
DataSourceSessionFactoryEntityManagerFactory
ConnectionSessionEntityManager

SessionFactory``EntityManagerFactoryDataSource``Session``EntityManagerConnectionÿҪݿʱҪȡµ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򵥣ﲻٶ

MyBatis

: 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ȣҪм

  1. ѯҪֶṩMapperʵԱResultSetÿһбΪJava
  2. ɾIJIJбҪֶ룬UserʵΪ[user.id, user.name, user.email]бȽ鷳

JdbcTemplateȷԣÿζȡһݿǻ棬ִеSQLȫȷģȱǴȽϷINSERT INTO users VALUES (?,?,?)Ǹӡ

ԣȫԶORMHibernateдȫJdbcTemplate֮䣬һְԶORMֻResultSetԶӳ䵽Java BeanԶJava BeanԼдSQLMyBatisһְԶORMܡ

SpringмMyBatis

ȣҪMyBatisΣSpringûHibernateöMyBatisļɣԣҪMyBatisٷԼһSpringɵĿ⣺

  • org.mybatis:mybatis:3.5.11
  • org.mybatis:mybatis-spring:3.0.0

ǰһȴDataSourceDZزٵģ

@Configuration
@ComponentScan
@EnableTransactionManagement
@PropertySource("jdbc.properties")
public class AppConfig {
    @Bean
    DataSource createDataSource() { ... }
}

ٻعһHibernateJPASessionFactory``EntityManagerFactoryMyBatis֮ӦSqlSessionFactory``SqlSession

JDBCHibernateJPAMyBatis
DataSourceSessionFactoryEntityManagerFactorySqlSessionFactory
ConnectionSessionEntityManagerSqlSession

ɼ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ݿⷽݿ⡣

XML

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