浅谈JPA+Hibernate与mybatis使用心得

本文作者分享了一年多来使用JPA+Hibernate作为持久层框架的心得,指出在处理复杂业务时,面向对象的方式可能导致代码可读性和维护性下降,转而倾向于直接使用SQL。然而,直接写SQL可能存在SQL注入问题,作者提供了参数绑定工具类的代码,并讨论了JPA的SQL参数绑定可能出现的问题。相比之下,作者认为Mybatis在参数绑定和XML配置方面更直观,更适合当前项目需求。目前项目同时使用JPA和Mybatis。文章还提到了Mybatis的依赖、配置和代码结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

手上的项目做了一年多,一直在使用JPA+Hibernate作为持久层的框架,前期使用了面向对象的方式,发现当业务很复杂时,代码可读性太差,也难维护,不如直接上sql来的快,但是有些细节问题没注意,导致后期重构时工作量很大,就是sql注入的问题,直接写sql没有使用占位符,这里就要仔细说一说了。JPA使用占位符是在sql中使用?或者:key,我选择的是用:key的方式,假设有是个查询条件,此时需要判空十次分别设置key值,然后再判断十次来setParameter()给占位符赋值,这个事情是在重构的时候做的,可想而知工作量,我比较喜欢偷懒,就写了个绑定参数的工具类,代码在最下方,给可能需要用的朋友,写的不是很好,希望有人可以给我提意见。但是还是会出现一些问题,比如参数类型的问题,或者一些特殊业务的问题,但这些问题都是JPA中sql参数绑定的问题,也可能是我没有找到解决办法,后来就想到了mybatis,也是直接写sql,很直接,很舒服,参数绑定也很自然,以前觉得写这些xml文件很麻烦,现在觉得比起JPA的sql绑定会出现一些奇奇怪怪的问题,我还是愿意选择mybatis。但是项目之前的JPA+Hibernate又不能丢,所以现在项目的情况是JPA和mybatis同时存在。上一下代码,记录一下。

以上纯属个人工作杂记。

1.依赖:这里只放了mybatis的依赖,新项目还需要jdbc-connect,连接池等依赖

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>

 2.mybatis的配置:mybatis-config.xml直接放在resource下面

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- mybatis全局设置 -->
    <settings>
        <!--使用数据库自增id-->
        <setting name="useGeneratedKeys" value="true" />
        <setting name="useColumnLabel" value="true" />
        <!-- 开启驼峰命名规范-->
        <setting name="mapUnderscoreToCamelCase" value="true" />
    </settings>

</configuration>

 3.spring集成mybatis:这里注意一下,dataSource可以与Hibernate共用

<bean id="dataSource" class="com.gtis.support.JndiSupportBasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${landtax.db.driver}"/>
        <property name="jndiName" value="${landtax.db.jndi}"/>
        <property name="url" value="${landtax.db.url}"/>
        <property name="username" value="${landtax.db.username}"/>
        <property name="password" value="${landtax.db.password}"/>
    </bean> 
<!-- mybatis文件配置,扫描所有mapper文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="typeAliasesPackage" value="cn.gtmap.landtax.entity"/>
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>
    <!-- spring与mybatis整合配置,扫描所有dao,指定的映射器类是接口,接口方法可以用注解来指定 SQL 语句,但是 MyBatis 的映射器 XML 文件也可以用。 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--扫描dao接口-->
        <property name="basePackage" value="cn.gtmap.landtax.dao"/>
        <!--注入sqlSessionFactory-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

 4.mybatis代码骨架:

dao(放dao接口),mapper(注意xml中namespace要与dao一致),entity,service

 

JPA参数绑定(http接口中查询参数 Object 为实体类对象或者Map都可以处理,Query为JPA的对象)

import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.persistence.Parameter;
import javax.persistence.Query;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @Auther: <a href="mailto:jiwang@gtmap.cn">jiwang</a>
 * @Version: 1.0, 2018/11/27
 * @Description:sql参数绑定处理工具
 */
@Component
public class SqlBinderUtil {
    private static final Logger LOGGER = Logger.getLogger(SqlBinderUtil.class);

    /**
        *@Author: jiwang
        *@Date: 8:47 2018/11/30
        *@Param: [o, query]
        *@return: void
        *@Description: sql绑定参数  有两种查询参数形式,一种是实体类queryBean,一种Map类型的参数
        **/
    public void sqlBindParameter(Object o, Query query){
        if (o instanceof Map){
            this.sqlBindParameterByMapParam((Map) o,query);
        }else {
            this.sqlBindParameterByQueryBean(o,query);
        }
    }

    /**
        *@Author: jiwang
        *@Date: 9:38 2018/12/4
        *@Param: [param, query]
        *@return: void
        *@Description:处理Map类型参数的sql绑定
        **/
    public void sqlBindParameterByMapParam(Map param,Query query){
        Set<Parameter<?>> parameters = query.getParameters();
        Iterator<Parameter<?>> setIterator = parameters.iterator();
        while (setIterator.hasNext()){
            Parameter<?> parameter = setIterator.next();
            String key = parameter.getName();
            if (param.containsKey(key)){
                query.setParameter(key,param.get(key));
            }
        }
    }
    /**
        *@Author: jiwang
        *@Date: 9:38 2018/12/4
        *@Param: [o, query]
        *@return: void
        *@Description:处理实体类类型参数的sql绑定
        **/
    public void sqlBindParameterByQueryBean(Object o, Query query){
        Class clazz = o.getClass();
        Set<Parameter<?>> parameterSet = query.getParameters();
        Iterator<Parameter<?>> iterator = parameterSet.iterator();
        while (iterator.hasNext()){
            String key = iterator.next().getName();
            try {
                Field field = clazz.getDeclaredField(key);
                PropertyDescriptor pd = new PropertyDescriptor(field.getName(),clazz);
                Method method = pd.getReadMethod();
                String value = (String) method.invoke(o);
                query.setParameter(key,value);
            }  catch (IntrospectionException e) {
                LOGGER.info(e);
            } catch (IllegalAccessException e) {
                LOGGER.info(e);
            } catch (InvocationTargetException e) {
                LOGGER.info(e);
            } catch (NoSuchFieldException e) {
                LOGGER.info(e);
            }
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值