在數(shù)據(jù)持久化的世界中,JDBC就像自行車坞琴,對于份內(nèi)的工作它能完成的很好哨查。隨著應(yīng)用程序越來越復(fù)雜,對持久化的要求也越來越復(fù)雜剧辐。我們需要將對象的屬性映射到數(shù)據(jù)庫的列上解恰,并且需要自動生成語句和查詢锋八,這樣我們就能從無休止的問號字符串中解脫出來。
一护盈、Hibernate
還是以Spittr應(yīng)用為例來具體闡述Hibernate的使用挟纱。
我們定義Spitter、Spittle兩個實體類腐宋。
package spittr.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Spitter {
private Spitter() {}
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
? @Column(name="username")
private String username;
? @Column(name="password")
private String password;
? @Column(name="fullname")
private String fullName;
? @Column(name="email")
private String email;
? @Column(name="updateByEmail")
private boolean updateByEmail;
? public Spitter(Long id, String username, String password, String fullName,
? ? ? ? String email, boolean updateByEmail) {
this.id = id;
? ? ? this.username = username;
? ? ? this.password = password;
? ? ? this.fullName = fullName;
? ? ? this.email = email;
? ? ? this.updateByEmail = updateByEmail;
? }
public Long getId() {return id;}
public String getUsername() {return username;}
public String getPassword() {return password; }
public String getFullName() {return fullName;}
public String getEmail() {return email;}
public boolean isUpdateByEmail() {return updateByEmail; }
}
package spittr.domain;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class Spittle {
private Spittle() {}
@Id
? @GeneratedValue(strategy=GenerationType.IDENTITY)
private Longid;
? @ManyToOne
? @JoinColumn(name="spitter")
private Spitter spitter;
? @Column
? private String message;
? @Column
? private Date postedTime;
? public Spittle(Long id, Spitter spitter, String message, Date postedTime) {
this.id = id;
? ? ? this.spitter = spitter;
? ? ? this.message = message;
? ? ? this.postedTime = postedTime;
? }
public Long getId() {
return this.id;
? }
public String getMessage() {
return this.message;
? }
public Date getPostedTime() {
return this.postedTime;
? }
public Spitter getSpitter() {
return this.spitter;
? }
}
@Entity注解表示這是一個實體類紊服,@Id注解代表這是數(shù)據(jù)表的primary key ,@GeneratedValue代表這是自動生成的列,
@Column注解將數(shù)據(jù)表的一列與類的屬性綁定胸竞,不指定name屬性則代表和變量名相同欺嗤,@ManyToOne注解代表會有多個Spittle參照同一個Spitter,?@JoinColumn注解代表參考spitter列卫枝。
這樣就實現(xiàn)了類屬性和數(shù)據(jù)表項的綁定煎饼。
同樣我們定義SpitterRepository、SpittleRepository接口校赤。
package spittr.db;
import java.util.List;
import spittr.domain.Spittle;
public interface SpittleRepository {
long count();
? List?findRecent();
? List?findRecent(int count);
? Spittle findOne(long id);
? Spittle save(Spittle spittle);
? List?findBySpitterId(long spitterId);
? void delete(long id);
}
package spittr.db;
import java.util.List;
import spittr.domain.Spitter;
public interface SpitterRepository {
long count();
? Spitter save(Spitter spitter);
? Spitter findOne(long id);
? Spitter findByUsername(String username);
? List?findAll();
}
我們先看看如何配置Hibernate 下面是RepositoryTestConfig.java吆玖。
package spittr.db.hibernate4;
import java.io.IOException;
import java.util.Properties;
import javax.inject.Inject;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
@Configuration
@EnableTransactionManagement
@ComponentScan
public class RepositoryTestConfigimplements TransactionManagementConfigurer {
@Inject
? private SessionFactorysessionFactory;
? @Bean
? public DataSource dataSource() {
EmbeddedDatabaseBuilder edb =new EmbeddedDatabaseBuilder();
? ? edb.setType(EmbeddedDatabaseType.H2);
? ? edb.addScript("spittr/db/hibernate4/schema.sql");
? ? edb.addScript("spittr/db/hibernate4/test-data.sql");
? ? EmbeddedDatabase embeddedDatabase = edb.build();
? ? return embeddedDatabase;
? }
public PlatformTransactionManager annotationDrivenTransactionManager() {
System.out.println(sessionFactory);
? ? HibernateTransactionManager transactionManager =new HibernateTransactionManager();
? ? transactionManager.setSessionFactory(sessionFactory);
? ? return transactionManager;
? }
@Bean
? public SessionFactory sessionFactoryBean() {
try {
LocalSessionFactoryBean lsfb =new LocalSessionFactoryBean();
? ? ? lsfb.setDataSource(dataSource());
? ? ? lsfb.setPackagesToScan("spittr.domain");
? ? ? Properties props =new Properties();
? ? ? props.setProperty("dialect", "org.hibernate.dialect.H2Dialect");
? ? ? lsfb.setHibernateProperties(props);
? ? ? lsfb.afterPropertiesSet();
? ? ? SessionFactory object = lsfb.getObject();
? ? ? return object;
? ? }catch (IOException e) {
return null;
? ? }
}
}
這里我們聲明它是一個配置類并且啟用了組件掃描和事務(wù)管理。
@Inject和@Autowired基本相同马篮,同樣dataBase bean為數(shù)據(jù)源配置沾乘,annotationDrivenTransactionManager bean 為事務(wù)處理,
使用Hibernate所需要的主要接口時org.hibernate.Session浑测。Session接口提供了基本的數(shù)據(jù)訪問功能翅阵,如保存、更新迁央、刪除以及從數(shù)據(jù)庫加載對象的功能掷匠。通過Hibernate的Session接口,應(yīng)用程序的Repository能夠滿足所有的持久化需求岖圈。
SessionFactory主要負責(zé)Hibernate Session的打開槐雾,關(guān)閉以及管理。
dataSource和hibernateProperties屬性聲明了從哪里獲取數(shù)據(jù)庫連接以及要使用哪一種數(shù)據(jù)庫幅狮。這里不再列出Hibernate配置文件,使用packageToScan屬性告訴Spring掃描一個或多個包以查找域類株灸,這些類表明要使用Hibernate進行持久化崇摄,這些類可以使用的注解包括JPA的@Entity或@MappedSuperclass以及Hibernate的Entity。
了解完Hibernate的配置之后我們開始編寫HibernateSpitterRepository和HibernateSpittleRepository他們分別實現(xiàn)SpitterRepository接口和SpittleRepository接口慌烧。
package spittr.db.hibernate4;
import java.io.Serializable;
import java.util.List;
import javax.inject.Inject;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;
import spittr.db.SpitterRepository;
import spittr.domain.Spitter;
@Repository
public class HibernateSpitterRepository implements SpitterRepository {
private SessionFactory sessionFactory;
@Inject
public HibernateSpitterRepository(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory; //<co id="co_InjectSessionFactory"/>
}
private Session currentSession() {
return sessionFactory.getCurrentSession();//<co id="co_RetrieveCurrentSession"/>
}
public long count() {
return findAll().size();
}
public Spitter save(Spitter spitter) {
Serializable id = currentSession().save(spitter);? //<co id="co_UseCurrentSession"/>
return new Spitter((Long) id,
spitter.getUsername(),
spitter.getPassword(),
spitter.getFullName(),
spitter.getEmail(),
spitter.isUpdateByEmail());
}
public Spitter findOne(long id) {
return (Spitter) currentSession().get(Spitter.class, id);
}
public Spitter findByUsername(String username) {
return (Spitter) currentSession()
.createCriteria(Spitter.class)
.add(Restrictions.eq("username", username))
.list().get(0);
}
public List<Spitter> findAll() {
return (List<Spitter>) currentSession()
.createCriteria(Spitter.class).list();
}
}
package spittr.db.hibernate4;
import java.io.Serializable;
import java.util.List;
import javax.inject.Inject;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;
import spittr.db.SpittleRepository;
import spittr.domain.Spittle;
@Repository
public class HibernateSpittleRepositoryimplements SpittleRepository {
private SessionFactorysessionFactory;
? @Inject
? public HibernateSpittleRepository(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
? }
private Session currentSession() {
return sessionFactory.getCurrentSession();//
? }
public long count() {
return findAll().size();
? }
public List?findRecent() {
return findRecent(10);
? }
public List?findRecent(int count) {
return (List) spittleCriteria()
.setMaxResults(count)
.list();
? }
public Spittle findOne(long id) {
return (Spittle) currentSession().get(Spittle.class, id);
? }
public Spittle save(Spittle spittle) {
Serializable id = currentSession().save(spittle);
? ? ? return new Spittle(
(Long) id,
? ? ? ? spittle.getSpitter(),
? ? ? ? spittle.getMessage(),
? ? ? ? spittle.getPostedTime());
? }
public List?findBySpitterId(long spitterId) {
return spittleCriteria()
.add(Restrictions.eq("spitter.id", spitterId))
.list();
? }
public void delete(long id) {
currentSession().delete(findOne(id));
? }
public List?findAll() {
return (List) spittleCriteria().list();
? }
private Criteria spittleCriteria() {
return currentSession()
.createCriteria(Spittle.class)
.addOrder(Order.desc("postedTime"));
? }
}
我們將一個SessionFactory注入到HibernateSpitterRepository和HibernateSpittleRepository的sessionFactory屬性中逐抑,在currentSession()方法中我們使用這個sessionFactory來獲取當(dāng)前事務(wù)的Session。
我們使用了@Repository注解屹蚊,它能夠被組件掃描掃描到厕氨,不必顯示聲明进每,它還會捕獲平臺相關(guān)的異常,然后使用Spring統(tǒng)一非檢查型異常重新拋出命斧。
數(shù)據(jù)類同數(shù)據(jù)庫的表存在對應(yīng)關(guān)系田晚,使用Hibernate操作數(shù)據(jù)類時,Hibernate會將之轉(zhuǎn)換為對數(shù)據(jù)庫中對應(yīng)表的操作国葬。
org.hibernate.Criteria接口表示特定持久類的一個查詢贤徒。Session是 Criteria實例的工廠。currentSession()
.createCriteria(Spittle.class)表示Spittle類的一個查詢汇四。參見:http://www.baike.com/wiki/criteria
session.save()方法返回一個生成的id接奈,該id為Serializable類型。
接下來測試一下
package spittr.db.hibernate4;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import spittr.db.SpitterRepository;
import spittr.domain.Spitter;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = RepositoryTestConfig.class)
public class SpitterRepositoryTest {
@Autowired
? SpitterRepository spitterRepository;
@Test
@Transactional
? public void findAll() {
List spitters =spitterRepository.findAll();
? ? assertEquals(4, spitters.size());
? ? assertSpitter(0, spitters.get(0));
? ? assertSpitter(1, spitters.get(1));
? ? assertSpitter(2, spitters.get(2));
? ? assertSpitter(3, spitters.get(3));
? }
}
二通孽、JPA-Hibernate
我們嘗試開發(fā)基于JPA的Repository序宦。Java持久化API(Java Persistence API,JPA)誕生在EJB2實體Bean的廢墟之上背苦,并成為下一代Java持久化標(biāo)準(zhǔn)互捌。JPA是基于POJO的持久化機制。
以Spittr應(yīng)用為例糠惫,我們首先看看JPAConfig類
package spittr.db.jpa;
import javax.inject.Inject;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
@Configuration
@ComponentScan
public class JpaConfig {
@Bean
? public DataSource dataSource() {
EmbeddedDatabaseBuilder edb =new EmbeddedDatabaseBuilder();
? ? edb.setType(EmbeddedDatabaseType.H2);
? ? edb.addScript("spittr/db/jpa/schema.sql");
? ? edb.addScript("spittr/db/jpa/test-data.sql");
? ? EmbeddedDatabase embeddedDatabase = edb.build();
? ? return embeddedDatabase;
? }
@Bean
? public LocalContainerEntityManagerFactoryBean emf(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
LocalContainerEntityManagerFactoryBean emf =new LocalContainerEntityManagerFactoryBean();
? ? emf.setDataSource(dataSource);
? ? emf.setPersistenceUnitName("spittr");
? ? emf.setJpaVendorAdapter(jpaVendorAdapter);
? ? emf.setPackagesToScan("spittr.domain");
? ? return emf;
? }
@Bean
? public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter adapter =new HibernateJpaVendorAdapter();
? ? adapter.setDatabase(Database.H2);
? ? adapter.setShowSql(true);
? ? adapter.setGenerateDdl(false);
? ? adapter.setDatabasePlatform("org.hibernate.dialect.H2Dialect");
? ? return adapter;
? }
@Configuration
@EnableTransactionManagement
? public static class TransactionConfig implements TransactionManagementConfigurer {
@Inject
? ? private EntityManagerFactory emf;
? ? public PlatformTransactionManager annotationDrivenTransactionManager() {
JpaTransactionManager transactionManager =new JpaTransactionManager();
? ? ? transactionManager.setEntityManagerFactory(emf);
? ? ? return transactionManager;
? ? }
}
}
基于JPA的應(yīng)用程序需要使用EntityManagerFactory的實現(xiàn)類來獲得EntityManager實例疫剃。JPA定義了應(yīng)用程序管理類型和容器管理類型的實體管理器,這兩種實體管理器實現(xiàn)了同一個EntityManager接口硼讽。關(guān)鍵的區(qū)別不在于EntityManager本身巢价,而是在于EntityManager的創(chuàng)建和管理方式。顧名思義固阁,前者由應(yīng)用程序創(chuàng)建和管理壤躲,后者由Java EE創(chuàng)建和管理。
JpaVendorAdapter 屬性用于指明所使用的是哪一個廠商的JPA實現(xiàn)备燃。
使用LocalContainerEntityManagerFactoryBean來配置容器管理類型的JPA碉克。
接下來編寫基于JPA的Repository:JpaSpitterRepository、JpaSpittleRepository
package spittr.db.jpa;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import spittr.db.SpitterRepository;
import spittr.domain.Spitter;
@Repository
public class JpaSpitterRepository implements SpitterRepository {
@PersistenceContext
? private EntityManager entityManager;
? public long count() {
return findAll().size();
? }
public Spitter save(Spitter spitter) {
entityManager.persist(spitter);
? ? ? return spitter;
? }
public Spitter findOne(long id) {
return entityManager.find(Spitter.class, id);
? }
public Spitter findByUsername(String username) {
return (Spitter)entityManager.createQuery("select s from Spitter s where s.username=?").setParameter(1, username).getSingleResult();
? }
public List?findAll() {
return (List)entityManager.createQuery("select s from Spitter s").getResultList();
? }
}
package spittr.db.jpa;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import spittr.db.SpittleRepository;
import spittr.domain.Spittle;
@Repository
public class JpaSpittleRepository implements SpittleRepository {
@PersistenceContext
? private EntityManager entityManager;
? public long count() {
return findAll().size();
? }
public List?findRecent() {
return findRecent(10);
? }
public List?findRecent(int count) {
return (List)entityManager.createQuery("select s from Spittle s order by s.postedTime desc")
.setMaxResults(count)
.getResultList();
? }
public Spittle findOne(long id) {
return entityManager.find(Spittle.class, id);
? }
public Spittle save(Spittle spittle) {
entityManager.persist(spittle);
? ? return spittle;
? }
public List?findBySpitterId(long spitterId) {
return (List)entityManager.createQuery("select s from Spittle s, Spitter sp where s.spitter = sp and sp.id=? order by s.postedTime desc")
.setParameter(1, spitterId)
.getResultList();
? }
public void delete(long id) {
entityManager.remove(findOne(id));
? }
public List?findAll() {
return (List)entityManager.createQuery("select s from Spittle s").getResultList();
? }
}
由于EntityManager并不是線程安全的并齐,一般并不適合注入到Repository這樣共享的單例Bean中漏麦,我們使用@PersistanceContext注解解決這個問題。@PersistanceContext并沒有注入一個真正的EntityManager况褪,而是給了它一個EntityManager的代理撕贞。真正的EntityManager是與當(dāng)前事務(wù)相關(guān)聯(lián)的那一個,如果不存在测垛,就會創(chuàng)建一個新的捏膨。@Transactional表明這個Repository中的持久化方法是在事務(wù)上下文中執(zhí)行的。
以下是測試類部分代碼:
package spittr.db.jpa;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import spittr.db.SpitterRepository;
import spittr.domain.Spitter;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=JpaConfig.class)
public class SpitterRepositoryTest {
@Autowired
? SpitterRepository spitterRepository;
@Test
@Transactional
? public void findAll() {
List spitters =spitterRepository.findAll();
? ? ? assertEquals(4, spitters.size());
? ? ? assertSpitter(0, spitters.get(0));
? ? ? assertSpitter(1, spitters.get(1));
? ? ? assertSpitter(2, spitters.get(2));
? ? ? assertSpitter(3, spitters.get(3));
? }
}
三、借助Spring Data實現(xiàn)自動化的JPA Repository
盡管JPA-Hibernate代碼已經(jīng)很簡單号涯,但依然會有直接與EntityManager交互來查詢數(shù)據(jù)庫目胡。我們借助Spring Data,以接口定義的方式創(chuàng)建Repository链快。
package spittr.db;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import spittr.domain.Spittle;
public interface SpittleRepositoryextends JpaRepository, SpittleRepositoryCustom {
ListfindBySpitterId(long spitterId);
}
package spittr.db;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import spittr.domain.Spitter;
public interface SpitterRepository extends JpaRepository, SpitterSweeper {
Spitter findByUsername(String username);
List findByUsernameOrFullNameLike(String username, String fullName);
}
這里我們并不需要實現(xiàn)findBySpittleId方法誉己,findByUsername方法,findByUsernameOrFullNameLike方法久又,方法簽名已經(jīng)告訴Spring Data JPA足夠的信息來創(chuàng)建這個方法的實現(xiàn)了巫延。
編寫Spring Data JPA Repository 的關(guān)鍵在于要從一組接口中選一個進行擴展,這里SpittleRepository擴展了Spring Data JPA 的JpaRepository地消。通過這種方式炉峰,JpaRepository進行了參數(shù)化,所以它就能知道這是一個用來持久化Spitter對象的Repository脉执,并且Spitter對象的ID類型為Long疼阔。
接下來我們看看自定義查詢方法。
package spittr.db;
public interface Spitter Sweeper {
int eliteSweep();
}
package spittr.db;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
public class SpitterRepositoryImpl implements SpitterSweeper {
@PersistenceContext
? private EntityManager em;
? public int eliteSweep() {
String update =
"UPDATE Spitter spitter " +
"SET spitter.status = 'Elite' " +
"WHERE spitter.status = 'Newbie' " +
"AND spitter.id IN (" +
"SELECT s FROM Spitter s WHERE (" +
"? SELECT COUNT(spittles) FROM s.spittles spittles) > 10000" +
")";
? ? ? return em.createQuery(update).executeUpdate();
? }
}
復(fù)雜查詢可以自己編寫半夷。
配置Spring Data? JPA
package spittr.db;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
@Configuration
@EnableJpaRepositories("spitter.db")
public class SpringDataJpaConfig {
@Bean
? public DataSourcedataSource() {
return new EmbeddedDatabaseBuilder()
.addScript("classpath:/com/habuma/spitter/db/jpa/schema.sql")
.addScript("classpath:/com/habuma/spitter/db/jpa/test-data.sql")
.build();
? }
@Bean
? public JpaTransactionManagertransactionManager() {
return new JpaTransactionManager(); // does this need an emf???
? }
@Bean
? public HibernateJpaVendorAdapterjpaVendorAdapter() {
HibernateJpaVendorAdapter adapter =new HibernateJpaVendorAdapter();
? ? adapter.setDatabase(Database.H2);
? ? adapter.setShowSql(false);
? ? adapter.setGenerateDdl(true);
? ? return adapter;
? }
@Bean
? public Objectemf() {
LocalContainerEntityManagerFactoryBean emf =new LocalContainerEntityManagerFactoryBean();
? ? emf.setDataSource(dataSource());
? ? emf.setPersistenceUnitName("spitter");
? ? emf.setJpaVendorAdapter(jpaVendorAdapter());
? ? return emf;
? }
}
@EnableJpaRepositories("spitter.db")會掃描spittr.db包查找擴展自Spring Data JPA Repository接口的所有接口婆廊,如果發(fā)現(xiàn)了擴展自Repository的接口,他會自動(在應(yīng)用啟動的時候)生成這個接口的實現(xiàn)巫橄。