spring-data-jpa自定義repository來實現原生sql

Spring Data JPA中的Repository是接口,是JPA根據方法名幫我們自動生成的。但很多時候,我們需要爲Repository提供一些自定義的實現。今天我們看看如何爲Repository添加自定義的方法。

自定義Repository接口

首先我們來添加一個自定義的接口:

  • 添加BaseRepository接口
  • BaseRepository繼承了JpaRepository,這樣可以保證所有Repository都有jpa提供的基本方法。
  • BaseRepository上添加@NoRepositoryBean標註,這樣Spring Data Jpa在啓動時就不會去實例化BaseRepository這個接口
/**
 * Created by liangkun on 2016/12/7.
 */
@NoRepositoryBean
public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID> {

    //sql原生查詢
    List<Map<String, Object>> listBySQL(String sql);
}

接下來實現BaseRepository接口,並繼承SimpleJpaRepository類,使其擁有Jpa Repository的提供的方法實現。

/**
 * Created by liangkun on 2017/12/7.
 */
public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T,ID> implements BaseRepository<T,ID> {

    private final EntityManager entityManager;

    //父類沒有不帶參數的構造方法,這裏手動構造父類
    public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.entityManager = entityManager;
    }



    //通過EntityManager來完成查詢
    @Override
    public  List<Map<String, Object>> listBySQL(String sql) {
        return entityManager.createNativeQuery(sql).getResultList();
    }
}

這裏着重說下EntityManager

EntityManager是JPA中用於增刪改查的接口,它的作用相當於一座橋樑,連接內存中的java對象和數據庫的數據存儲。也可以根據他進行sql的原生查找。

源碼如下:

public interface EntityManager {
    
    <T> T find(Class<T> var1, Object var2);

    Query createNativeQuery(String var1);

    Query createNativeQuery(String var1, Class var2);

    Query createNativeQuery(String var1, String var2);
}

由上可以看出其有具體的原生查詢實現接口 createNativeQuery

接下來需要將我們自定義的Repository接口,通過工廠模式添加到Spring的容器中:

創建自定義RepositoryFactoryBean

接下來我們來創建一個自定義的RepositoryFactoryBean來代替默認的RepositoryFactoryBeanRepositoryFactoryBean負責返回一個RepositoryFactory,Spring Data Jpa 將使用RepositoryFactory來創建Repository具體實現。

查看JpaRepositoryFactoryBean的源碼,通過createRepositoryFactory返回JpaRepositoryFactory實例:

public class JpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable>
		extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> {

	private EntityManager entityManager;
	
	public JpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
		super(repositoryInterface);
	}
	
	@PersistenceContext
	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	@Override
	public void setMappingContext(MappingContext<?, ?> mappingContext) {
		super.setMappingContext(mappingContext);
	}

	@Override
	protected RepositoryFactorySupport doCreateRepositoryFactory() {
		return createRepositoryFactory(entityManager);
	}

	protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
		return new JpaRepositoryFactory(entityManager);
	}

	@Override
	public void afterPropertiesSet() {

		Assert.notNull(entityManager, "EntityManager must not be null!");
		super.afterPropertiesSet();
	}
}

終上我們可根據相應的規則進行創建自定義RepositoryFactoryBean

/**
 * Created by liangkun on 2018/07/20.
 */
public class BaseRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> {

    public BaseRepositoryFactoryBean(Class<? extends R> repositoryInterface) {
        super(repositoryInterface);
    }

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
        return new BaseRepositoryFactory(em);
    }

    //創建一個內部類,該類不用在外部訪問
    private static class BaseRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {

        private final EntityManager em;

        public BaseRepositoryFactory(EntityManager em) {
            super(em);
            this.em = em;
        }

        //設置具體的實現類是BaseRepositoryImpl
        @Override
        protected Object getTargetRepository(RepositoryInformation information) {
            return new BaseRepositoryImpl<T, I>((Class<T>) information.getDomainType(), em);
        }

        //設置具體的實現類的class
        @Override
        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return BaseRepositoryImpl.class;
        }
    }
}

自定義完成。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章