Jpa分表和复杂SQL转换成Pojo问题
2017-05-06 00:00
148 查看
最近公司项目需要一个对接的东西,大部分都是单表的CRUD,然后就想到用SpringBoot的JPA来做,这样可以省去很多的重复代码,但是需要解决几个问题:
单表的SQL,其实表的名称是变得,规则很像子表的规则,如何在Jpa中自动更换表名称
对于复杂的原生SQL,可以直接转换为Pojo,达到JdbcTemplate类似效果,并且要兼容1的要求
对于问题1:采用的是Hibernate的Interceptor来拦截执行的SQL,然后更换表名称,拦截部分代码如下:
其中MySQLUtils.refactor是借助durid的SQL解析来替换表名称。
为了不让每个方法都显示的设置这个in,新增一个辅助类:SqlExecuteHelper,代码如下:
ICallBack只是一个简单的回调接口。
然后配置SpringBoot的Hibernate的Interceptor:
spring.jpa.properties.hibernate.ejb.interceptor.session_scoped=HibernateSQLInterceptor
这样Jpa的SQL就会被拦截处理,并且更改表名称。
对于问题2:首先继承自AliasedTupleSubsetResultTransformer来实现Pojo的转换。
然后定义一个JpaTemplate:
这样就可以实现复杂SQL到Pojo的映射。
单表的SQL,其实表的名称是变得,规则很像子表的规则,如何在Jpa中自动更换表名称
对于复杂的原生SQL,可以直接转换为Pojo,达到JdbcTemplate类似效果,并且要兼容1的要求
对于问题1:采用的是Hibernate的Interceptor来拦截执行的SQL,然后更换表名称,拦截部分代码如下:
public class HibernateSQLInterceptor extends EmptyInterceptor{ /** * */ private static final long serialVersionUID = -8497637816391956683L; private static ThreadLocal<Integer> THREADLOCAL = new ThreadLocal<>(); public static void set(Integer in){ THREADLOCAL .set(in); } public static void remove(){ THREADLOCAL .remove(); } @Override public String onPrepareStatement(String sql) { Integer in= THREADLOCAL .get(); if (null == in) { return sql; } return MySQLUtils.refactor(sql, in); } }
其中MySQLUtils.refactor是借助durid的SQL解析来替换表名称。
为了不让每个方法都显示的设置这个in,新增一个辅助类:SqlExecuteHelper,代码如下:
public class SqlExecuteHelper { /** * 设置in到线程局部变量,会在 HibernateSQLInterceptor 里面的onPrepareStatement改写SQL * @param in * @param callBack * @return */ public static <T> T execute(int in,ICallBack<T> callBack){ T result ; try { HibernateSQLInterceptor.setIn(in); result = callBack.callback(); } finally{ HibernateSQLInterceptor.remove(); } return result; } }
ICallBack只是一个简单的回调接口。
然后配置SpringBoot的Hibernate的Interceptor:
spring.jpa.properties.hibernate.ejb.interceptor.session_scoped=HibernateSQLInterceptor
这样Jpa的SQL就会被拦截处理,并且更改表名称。
对于问题2:首先继承自AliasedTupleSubsetResultTransformer来实现Pojo的转换。
import java.beans.PropertyDescriptor; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.hibernate.transform.AliasedTupleSubsetResultTransformer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanWrapper; import org.springframework.beans.NotWritablePropertyException; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.TypeMismatchException; import org.springframework.dao.DataRetrievalFailureException; import org.springframework.util.StringUtils; class BeanResultTransformer extends AliasedTupleSubsetResultTransformer { protected final Logger logger = LoggerFactory.getLogger(getClass()); /** * */ private static final long serialVersionUID = 7907702453067570731L; private static Map<Class<?>, BeanResultTransformer> TRANSFORMER_CACHE = new ConcurrentHashMap<>(); /** Map of the fields we provide mapping for */ private Map<String, PropertyDescriptor> mappedFields; /** Set of bean properties we provide mapping for */ private Set<String> mappedProperties; private Class<?> mappedClass; private BeanResultTransformer(Class<?> mappedClass) { initialize(mappedClass); } protected void initialize(Class<?> mappedClass) { this.mappedClass = mappedClass; this.mappedFields = new HashMap<String, PropertyDescriptor>(); this.mappedProperties = new HashSet<String>(); PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass); for (PropertyDescriptor pd : pds) { if (pd.getWriteMethod() != null) { this.mappedFields.put(lowerCaseName(pd.getName()), pd); String underscoredName = underscoreName(pd.getName()); if (!lowerCaseName(pd.getName()).equals(underscoredName)) { this.mappedFields.put(underscoredName, pd); } this.mappedProperties.add(pd.getName()); } } } @Override public Object transformTuple(Object[] tuple, String[] aliases) { Object mappedObject = BeanUtils.instantiateClass(this.mappedClass); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject); for (int i = 0; i < tuple.length; i++) { String alias = aliases[i]; String field = lowerCaseName(alias.replaceAll(" ", "")); PropertyDescriptor pd = this.mappedFields.get(field); if (pd != null) { try { try { bw.setPropertyValue(pd.getName(), tuple[i]); } catch (TypeMismatchException ex) { throw ex; } } catch (NotWritablePropertyException ex) { throw new DataRetrievalFailureException( "Unable to map column '" + i + "' to property '" + pd.getName() + "'", ex); } } else { logger.error("No property found for column '" + i + "' mapped to field '" + field + "'"); // No PropertyDescriptor found if (logger.isDebugEnabled()) { logger.debug("No property found for column '" + i + "' mapped to field '" + field + "'"); } } } return mappedObject; } @Override public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) { return false; } protected String lowerCaseName(String name) { return name.toLowerCase(Locale.US); } protected String underscoreName(String name) { if (!StringUtils.hasLength(name)) { return ""; } StringBuilder result = new StringBuilder(); result.append(lowerCaseName(name.substring(0, 1))); for (int i = 1; i < name.length(); i++) { String s = name.substring(i, i + 1); String slc = lowerCaseName(s); if (!s.equals(slc)) { result.append("_").append(slc); } else { result.append(s); } } return result.toString(); } public static BeanResultTransformer newInstance(Class<?> mappedClass) { BeanResultTransformer instance = TRANSFORMER_CACHE.get(mappedClass); if (null == instance) { instance = new BeanResultTransformer(mappedClass); TRANSFORMER_CACHE.put(mappedClass, instance); } return instance; } }
然后定义一个JpaTemplate:
import java.util.List; import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.Query; import org.hibernate.SQLQuery; import org.hibernate.transform.AliasToEntityMapResultTransformer; public class JpaTemplate { private EntityManager entityManager; public JpaTemplate(EntityManager entityManager) { this.entityManager = entityManager; } public <T> List<T> query(String sql, Class<T> requiredType) { return query(sql, new Object[0], requiredType); } @SuppressWarnings("unchecked") public <T> List<T> query(String sql, Object[] args, Class<T> requiredType) { Query query = entityManager.createNativeQuery(sql); query.unwrap(SQLQuery.class).setResultTransformer(BeanResultTransformer.newInstance(requiredType)); buildQueryArgs(query, args); return query.getResultList(); } public <T> T queryForObject(String sql, Class<T> requiredType) { return queryForObject(sql, new Object[0], requiredType); } @SuppressWarnings("unchecked") public <T> T queryForObject(String sql, Object[] args, Class<T> requiredType) { Query query = entityManager.createNativeQuery(sql); query.unwrap(SQLQuery.class).setResultTransformer(BeanResultTransformer.newInstance(requiredType)); buildQueryArgs(query, args); return (T) query.getSingleResult(); } public Map<String, Object> queryForMap(String sql) { return queryForMap(sql, new Object[0]); } @SuppressWarnings("unchecked") public Map<String, Object> queryForMap(String sql, Object[] args) { Query query = entityManager.createNativeQuery(sql); query.unwrap(SQLQuery.class).setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE); buildQueryArgs(query, args); return (Map<String, Object>) query.getSingleResult(); } public List<Map<String, Object>> queryForList(String sql) { return queryForList(sql, new Object[0]); } @SuppressWarnings("unchecked") public List<Map<String, Object>> queryForList(String sql, Object[] args) { Query query = entityManager.createNativeQuery(sql); query.unwrap(SQLQuery.class).setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE); buildQueryArgs(query, args); return query.getResultList(); } private void buildQueryArgs(Query query, Object[] args) { if (null != args) { for (int i = 1; i < args.length; i++) { query.setParameter(i, args[i]); } } } }
这样就可以实现复杂SQL到Pojo的映射。
相关文章推荐
- sql日期转换问题
- 关于Nhibernate中的hql与sql的转换问题
- 一个SQL语句的问题:行列转换
- sql中关于字符转换问题 cast用法
- SQL转换日期字段的问题——CONVERT转化函数的用法
- MS-SQL转换成ACCESS(解决自动编号的问题)
- 在hibernate中直接执行原生sql遇到类型转换问题
- 今天在csdn上遇到一个问题,是关于sql数据行列转换的,我的写法如下:
- SQL类型转换问题,
- sql中的text数据类型转换后相加的问题民
- SQL的行列转换问题
- 一个sql中常遇到的表结构转换问题
- 一个SQL语句的问题:行列转换
- 一个json-lib.jar转换复杂对象的问题?
- Sql 时间转换问题
- Access中SQL查询的数据类型转换问题
- 一个sql中常遇到的表结构转换问题
- Sql中关于行列转换问题
- 关于创建 LINQ to SQL 类时无法转换复数的问题(zhuan)
- sql中农历阳历之间的转换问题