DAO学习笔记 2

在上一篇文章我们曾说过,DAO 模式主要按下面的思路来实现:

  1.系统中的所有数据库访问都通过 DAO 进行以实现封装。

        2. 每个 DAO 实例负责一个主要域对象或实体。

        3.DAO 负责域对象的创建、读取(按主键)、更新和删除(CRUD)。

  4. DAO 可允许基于除主键之外的标准进行查询,返回值通常是DAO 负责的域对象集合。

  5.为了实现灵活性,DAO 不负责处理事务、会话或连接,而把这交给一个工具类。

下面进行具体介绍

统一 DAO的创建

 在实际的应用中,小茵茵使用的是Hibernate进行数据库的操作。在最开始的开发过程中,我给每一个DAO都创建了增,删,改,查的方法。但 是写到一半的时候,小茵茵就发现,其实每个DAO的操作都是类似的,于是我提取出了一个CommonDAO用于进行最基础的操作,这样不但让编写每个 DAO的工作变得简单了, 而且进行改动的时候也可以集中到一处。下面是CommonDAO的代码:

import java.util.Iterator;

import java.util.List;

 

import org.hibernate.Criteria;

import org.hibernate.Session;

import org.hibernate.criterion.Criterion;

import org.hibernate.criterion.Order;

 

/**

 * The abstract class of all the DAO all the methods are wrapped in transaction

 *

 * @author yiqian

 *

 */

public abstract class CommonDAO {

 

      /**

       * insert a object into DB

       *

       * @param obj

       * @throws Exception

       */

      protected void insert(Object obj) throws Exception {

 

            Session session = HibernateUtil.getCurrentSession();

            HibernateUtil.beginTransaction();

 

            session.save(obj);

 

            HibernateUtil.commitTransaction();

            HibernateUtil.closeSession();

      }

 

      /**

       * insert a list of the object in a transaction

       *

       * @param list

       *            a list of the objects

       *

       * @throws Exception

       */

      public void insert(List list) throws Exception {

 

            if (list == null)

                  throw new Exception(

                              "CommonDAO Error: insert a null list through DAO");

 

            Session session = HibernateUtil.getCurrentSession();

            HibernateUtil.beginTransaction();

 

            Iterator iter = list.iterator();

            while (iter.hasNext())

                  session.save(iter.next());

 

            HibernateUtil.commitTransaction();

            HibernateUtil.closeSession();

      }

 

      /**

       *

       * @param id

       *            primary key

       * @param myClass

       *            class of the Object

       * @return the object if the id is valid

       * @throws Exception

       */

      protected Object load(Class myClass, long id) throws Exception {

            Object obj = null;

 

            Session session = HibernateUtil.getCurrentSession();

            HibernateUtil.beginTransaction();

 

            obj = session.get(myClass, id);// use get instead of load

 

            HibernateUtil.commitTransaction();

            HibernateUtil.closeSession();

 

            return obj;

      }

 

      /**

       * delete a object from DB

       *

       * @param obj

       * @throws Exception

       */

      protected void delete(Object obj) throws Exception {

 

            Session session = HibernateUtil.getCurrentSession();

            HibernateUtil.beginTransaction();

 

            session.delete(obj);

 

            HibernateUtil.commitTransaction();

            HibernateUtil.closeSession();

 

      }

 

      /**

       * delete a list of objects in a transaction

       *

       * @param list

       * @throws Exception

       */

      public void delete(List list) throws Exception {

            if (list == null)

                  throw new Exception(

                              "CommonDAO Error: delete a null list through DAO");

            Iterator iter = list.iterator();

 

            Session session = HibernateUtil.getCurrentSession();

            HibernateUtil.beginTransaction();

 

            while (iter.hasNext())

                  session.delete(iter.next());

 

            HibernateUtil.commitTransaction();

            HibernateUtil.closeSession();

 

      }

 

      /**

       *

       * @param id

       * @throws Exception

       */

      protected void delete(Class myClass, long id) throws Exception {

 

            Session session = HibernateUtil.getCurrentSession();

            HibernateUtil.beginTransaction();

 

            Object obj = session.get(myClass, id);

 

            if (obj == null)

                  throw new Exception(myClass + ": delete with an invalid id");

            session.delete(obj);

 

            HibernateUtil.commitTransaction();

            HibernateUtil.closeSession();

 

      }

 

      /**

       *

       * @param myClass

       * @return all the data in corresponding table

       * @throws Exception

       */

      protected List findAll(Class myClass) throws Exception {

            List list = null;

 

            Session session = HibernateUtil.getCurrentSession();

            HibernateUtil.beginTransaction();

 

            Criteria criteria = session.createCriteria(myClass);

            list = criteria.list();

 

            HibernateUtil.commitTransaction();

            HibernateUtil.closeSession();

 

            return list;

 

      }

 

      /**

       * find all the rows according to the restricitions

       *

       * @param myClass

       * @param cris

       *            list of restrictions

       * @param order

       *            result set order

       * @return

       * @throws Exception

       */

      protected List findAll(Class myClass, List<Criterion> cris, Order order)

                  throws Exception {

            List list = null;

 

            Session session = HibernateUtil.getCurrentSession();

            Criteria criteria = session.createCriteria(myClass);

 

            // add the criterions

            if (cris != null) {

                  Iterator<Criterion> iter = cris.iterator();

                  while (iter.hasNext())

                        criteria.add(iter.next());

            }

 

            // add the order

            if (order != null)

                  criteria.addOrder(order);

 

            // begin the transaction

            HibernateUtil.beginTransaction();

 

            list = criteria.list();

 

            HibernateUtil.commitTransaction();

            HibernateUtil.closeSession();

 

            return list;

      }

 

      /**

       * find all the rows according to the restricitions

       *

       * @param myClass

       * @param cris

       *            restrictions

       * @return

       * @throws Exception

       */

      protected List findAll(Class myClass, List<Criterion> cris)

                  throws Exception {

            List list = null;

 

            Session session = HibernateUtil.getCurrentSession();

 

            Criteria criteria = session.createCriteria(myClass);

 

            // add the criterions

            if (cris != null) {

                  Iterator<Criterion> iter = cris.iterator();

                  while (iter.hasNext())

                        criteria.add(iter.next());

            }

 

            // begin the transaction

            HibernateUtil.beginTransaction();

 

            list = criteria.list();

 

            HibernateUtil.commitTransaction();

            HibernateUtil.closeSession();

 

            return list;

      }

 

      /**

       *

       * @param src -

       *            it should be an object returned by load method

       * @throws Exception

       */

      protected void update(Object obj) throws Exception {

 

            Session session = HibernateUtil.getCurrentSession();

            HibernateUtil.beginTransaction();

 

            session.update(obj);// make it bind with the session cache

 

            HibernateUtil.commitTransaction();

            HibernateUtil.closeSession();

 

      }

 

      /**

       * update a list of objects in a transaction

       *

       * @param src

       *            a list of objects loaded through DAO

       * @throws Exception

       */

      public void update(List list) throws Exception {

 

            if (list == null)

                  throw new Exception(

                              "CommonDAO Error: update a null list through DAO");

 

            Iterator iter = list.iterator();

 

            Session session = HibernateUtil.getCurrentSession();

            HibernateUtil.beginTransaction();

 

            while (iter.hasNext())

                  session.update(iter.next());// make it bind with the session cache

 

            HibernateUtil.commitTransaction();

            HibernateUtil.closeSession();

 

      }

 

}

 

 

创建一个特定的DAO

有了CommonDAO之后,我们就可以轻松的编写一个特定的DAO了。假定数据库中有一张TestAgent表,它的建表语句是:

 

DROP TABLE IF EXISTS `dev_autotest_user`.`at_testagent_ta`;

CREATE TABLE  `dev_autotest_user`.`at_testagent_ta` (

  `id_ta` bigint(20) unsigned NOT NULL auto_increment,

  `is_available_ta` tinyint(4) NOT NULL,

  `consumer_ta` bigint(20) default NULL,

  `type_ta` tinyint(4) NOT NULL,

  `agent_info_ta` varchar(1024) NOT NULL,

  UNIQUE KEY `id_ta` (`id_ta`)

) ENGINE=InnoDB AUTO_INCREMENT=63 DEFAULT CHARSET=utf8;

 

 

对应的持久化类TestAgent.java为:

 

public class TestAgent {

 

      private long id;

 

      private short is_available;

 

      private long consumer;

 

      private short type;

     

      private String agent_info;

 

      public TestAgent() {

            id = -1;

      }

 

      public long getConsumer() {

            return consumer;

      }

 

      public void setConsumer(long consumer) {

            this.consumer = consumer;

      }

 

      public long getId() {

            return id;

      }

 

      private void setId(long id) {

            this.id = id;

      }

 

      public short getIs_available() {

            return is_available;

      }

 

      public void setIs_available(short is_available) {

            this.is_available = is_available;

      }

 

      public short getType() {

            return type;

      }

 

      public void setType(short type) {

            this.type = type;

      }

     

     

      public String getAgent_info() {

            return agent_info;

      }

 

      public void setAgent_info(String agent_info) {

            this.agent_info = agent_info;

      }

 

      public String toString()

      {

            return "id:"+id+",isAvailable:"+this.is_available+",consumer:"+this.consumer+",type:"+this.type;

      }

     

 

那么Hibernate配置文件就是TestAgent.hbm.xml

 

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

 

<hibernate-mapping>

 

      <class name="com.ebay.autotest.data.po.TestAgent"

            table="at_testagent_ta">

 

            <id name="id" type="long" length="20">

                  <column name="id_ta" not-null="true" />

                  <generator class="increment" />

            </id>

 

            <property name="is_available" type="short" length="4">

                  <column name="is_available_ta" not-null="true" />

            </property>

 

            <property name="consumer" type="long" length="20">

                  <column name="consumer_ta" not-null="false" />

            </property>

 

            <property name="type" type="short" length="4">

                  <column name="type_ta" not-null="true" />

            </property>

 

            <property name="agent_info" type="string" length="1024">

                  <column name="agent_info_ta" not-null="true" />

            </property>

 

      </class>

 

</hibernate-mapping>

现在,我们创建TestAgentDAO

 

 

public class TestAgentDAO extends CommonDAO {

 

            public TestAgentDAO() {

                        // TODO Auto-generated constructor stub

            }

 

            /**

             *

             * @param agent

             * @return if the operation is successful

             * @throws Exception

             */

            public void insert(TestAgent agent) throws Exception {

                        super.insert(agent);

            }

 

            /**

             *

             * @param id

             *            primary key

             * @return TestAgent if the id is valid

             * @throws Exception

             */

            public TestAgent load(long id) throws Exception {

                        return (TestAgent) super.load(TestAgent.class, id);

 

            }

 

            /**

             *

             * @param agent ,

             *            it should be an agent loaded through DAO

             * @return

             * @throws Exception

             */

            public void delete(TestAgent agent) throws Exception {

                        super.delete(agent);

 

            }

 

            public void delete(long id) throws Exception {

 

                        super.delete(TestAgent.class, id);

            }

 

            public List<TestAgent> findAll() throws Exception {

                        return (List<TestAgent>) super.findAll(TestAgent.class);

 

            }

 

            /**

             *

             * @param available

             * @return

             * @throws Exception

             */

            public List<TestAgent> findAll(short available) throws Exception {

                        Criterion cri = Expression.eq("is_available", available);

                        List<Criterion> list = new ArrayList<Criterion>();

                        list.add(cri);

 

                        return (List<TestAgent>) super.findAll(TestAgent.class, list);

 

            }

 

            /**

             *

             * @param src -

             *            it should be an object returned by load method

             * @throws Exception

             */

            public void update(TestAgent src) throws Exception {

                        super.update(src);

            }

 

}

 

关于HibernateUtil

上面已经提到了,可以把对于sessiontransaction的操作都集中到HibernateUtil这个类中去。这里要感谢http://blog.csdn.net/lin_bei/archive/2006/08/10/1048051.aspx这篇文章的作者,他提供了一个非常强大的util类,让我学到了不少:)

下面是代码:

mport javax.naming.InitialContext;

import javax.naming.NamingException;

 

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.hibernate.Interceptor;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.Transaction;

import org.hibernate.cfg.Configuration;

import org.hibernate.cfg.Environment;

 

/**

 * make sure every thread get its own session

 *

 * @author yiqian

 *

 */

public class HibernateUtil {

 

            private static Log log = LogFactory.getLog(HibernateUtil.class);

 

            private static final String INTERCEPTOR_CLASS = "hibernate.util.interceptor_class";

 

            private static Configuration configuration;

            private static SessionFactory sessionFactory;

            private static ThreadLocal threadSession = new ThreadLocal();

            private static ThreadLocal threadTransaction = new ThreadLocal();

 

            private static boolean useThreadLocal = true;

 

            static {

                        // Create the initial SessionFactory from the default configuration

                        // files

                        try {

 

                                    // Replace with Configuration() if you don't use annotations or JDK

                                    // 5.0

                                    // configuration = new AnnotationConfiguration();

                                    configuration = new Configuration();

 

                                    // Read not only hibernate.properties, but also hibernate.cfg.xml

                                    configuration.configure();

 

                                    // Assign a global, user-defined interceptor with no-arg constructor

                                    String interceptorName = configuration

                                                            .getProperty(INTERCEPTOR_CLASS);

                                    if (interceptorName != null) {

                                                Class interceptorClass = HibernateUtil.class.getClassLoader()

                                                                        .loadClass(interceptorName);

                                                Interceptor interceptor = (Interceptor) interceptorClass

                                                                        .newInstance();

                                                configuration.setInterceptor(interceptor);

                                    }

 

                                    // Disable ThreadLocal Session/Transaction handling if CMT is used

                                    if (org.hibernate.transaction.CMTTransactionFactory.class

                                                            .getName()

                                                            .equals(

                                                                                    configuration

                                                                                                            .getProperty(Environment.TRANSACTION_STRATEGY)))

                                                useThreadLocal = false;

 

                                    if (configuration.getProperty(Environment.SESSION_FACTORY_NAME) != null) {

                                                // Let Hibernate bind it to JNDI

                                                configuration.buildSessionFactory();

                                    } else {

                                                // or use static variable handling

                                                sessionFactory = configuration.buildSessionFactory();

                                    }

 

                        } catch (Throwable ex) {

                                    // We have to catch Throwable, otherwise we will miss

                                    // NoClassDefFoundError and other subclasses of Error

                                    log.error("Building SessionFactory failed.", ex);

                                    throw new ExceptionInInitializerError(ex);

                        }

            }

 

            /**

             * Returns the original Hibernate configuration.

             *

             * @return Configuration

             */

            public static Configuration getConfiguration() {

                        return configuration;

            }

 

            /**

             * Returns the global SessionFactory.

             *

             * @return SessionFactory

             */

            public static SessionFactory getSessionFactory() {

                        SessionFactory sf = null;

                        String sfName = configuration

                                                .getProperty(Environment.SESSION_FACTORY_NAME);

                        if (sfName != null) {

                                    log.debug("Looking up SessionFactory in JNDI.");

                                    try {

                                                sf = (SessionFactory) new InitialContext().lookup(sfName);

                                    } catch (NamingException ex) {

                                                throw new RuntimeException(ex);

                                    }

                        } else {

                                    sf = sessionFactory;

                        }

                        if (sf == null)

                                    throw new IllegalStateException("SessionFactory not available.");

                        return sf;

            }

 

            /**

             * Closes the current SessionFactory and releases all resources.

             * <p>

             * The only other method that can be called on HibernateUtil after this one

             * is rebuildSessionFactory(Configuration).

             */

            public static void shutdown() {

                        log.debug("Shutting down Hibernate.");

                        // Close caches and connection pools

                        getSessionFactory().close();

 

                        // Clear static variables

                        configuration = null;

                        sessionFactory = null;

 

                        // Clear ThreadLocal variables

                        threadSession.set(null);

                        threadTransaction.set(null);

            }

 

            /**

             * Rebuild the SessionFactory with the static Configuration.

             * <p>

             * This method also closes the old SessionFactory before, if still open.

             * Note that this method should only be used with static SessionFactory

             * management, not with JNDI or any other external registry.

             */

            public static void rebuildSessionFactory() {

                        log.debug("Using current Configuration for rebuild.");

                        rebuildSessionFactory(configuration);

            }

 

            /**

             * Rebuild the SessionFactory with the given Hibernate Configuration.

             * <p>

             * HibernateUtil does not configure() the given Configuration object, it

             * directly calls buildSessionFactory(). This method also closes the old

             * SessionFactory before, if still open.

             *

             * @param cfg

             */

            public static void rebuildSessionFactory(Configuration cfg) {

                        log.debug("Rebuilding the SessionFactory from given Configuration.");

                        synchronized (sessionFactory) {

                                    if (sessionFactory != null && !sessionFactory.isClosed())

                                                sessionFactory.close();

                                    if (cfg.getProperty(Environment.SESSION_FACTORY_NAME) != null)

                                                cfg.buildSessionFactory();

                                    else

                                                sessionFactory = cfg.buildSessionFactory();

                                    configuration = cfg;

                        }

            }

 

            /**

             * Retrieves the current Session local to the thread. <p/> If no Session is

             * open, opens a new Session for the running thread. If CMT is used, returns

             * the Session bound to the current JTA container transaction. Most other

             * operations on this class will then be no-ops or not supported, the

             * container handles Session and Transaction boundaries, ThreadLocals are

             * not used.

             *

             * @return Session

             */

            public static Session getCurrentSession() {

                        if (useThreadLocal) {

                                    Session s = (Session) threadSession.get();

 

                                    if (s == null) {

                                                log.debug("Opening new Session for this thread.");

                                                s = getSessionFactory().openSession();

                                                threadSession.set(s);

                                    }

                                    return s;

                        } else {

                                    return getSessionFactory().getCurrentSession();

                        }

 

            }

 

            /**

             * Closes the Session local to the thread.

             * <p>

             * Is a no-op (with warning) if called in a CMT environment. Should be used

             * in non-managed environments with resource local transactions, or with

             * EJBs and bean-managed transactions.

             */

            public static void closeSession() {

                        if (useThreadLocal) {

                                    Session s = (Session) threadSession.get();

                                    threadSession.set(null);

                                    Transaction tx = (Transaction) threadTransaction.get();

                                    if (tx != null && (!tx.wasCommitted() || !tx.wasRolledBack()))

                                                throw new IllegalStateException(

                                                                        "Closing Session but Transaction still open!");

                                    if (s != null && s.isOpen()) {

                                                log.debug("Closing Session of this thread.");

                                                s.close();

                                    }

                        } else {

                                    log.warn("Using CMT/JTA, intercepted superfluous close call.");

                        }

            }

 

            /**

             * Start a new database transaction.

             * <p>

             * Is a no-op (with warning) if called in a CMT environment. Should be used

             * in non-managed environments with resource local transactions, or with

             * EJBs and bean-managed transactions. In both cases, it will either start a

             * new transaction or join the existing ThreadLocal or JTA transaction.

             */

            public static void beginTransaction() throws Exception {

                        if (useThreadLocal) {

                                    Transaction tx = (Transaction) threadTransaction.get();

                                    if (tx == null) {

                                                log.debug("Starting new database transaction in this thread.");

                                                tx = getCurrentSession().beginTransaction();

                                                threadTransaction.set(tx);

                                    }

                        } else {

                                    log.warn("Using CMT/JTA, intercepted superfluous tx begin call.");

                        }

            }

 

            /**

             * Commit the database transaction.

             * <p>

             * Is a no-op (with warning) if called in a CMT environment. Should be used

             * in non-managed environments with resource local transactions, or with

             * EJBs and bean-managed transactions. It will commit the ThreadLocal or

             * BMT/JTA transaction.

             */

            public static void commitTransaction() throws Exception {

                        if (useThreadLocal) {

                                    Transaction tx = (Transaction) threadTransaction.get();

                                    try {

                                                if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {

                                                            log

                                                                                    .debug("Committing database transaction of this thread.");

                                                            tx.commit();

                                                }

                                                threadTransaction.set(null);

                                    } catch (RuntimeException ex) {

                                                log.error(ex);

                                                rollbackTransaction();

                                                throw ex;

                                    }

                        } else {

                                    log.warn("Using CMT/JTA, intercepted superfluous tx commit call.");

                        }

            }

 

            /**

             * Rollback the database transaction.

             * <p>

             * Is a no-op (with warning) if called in a CMT environment. Should be used

             * in non-managed environments with resource local transactions, or with

             * EJBs and bean-managed transactions. It will rollback the resource local

             * or BMT/JTA transaction.

             */

            public static void rollbackTransaction() throws Exception {

                        if (useThreadLocal) {

                                    Transaction tx = (Transaction) threadTransaction.get();

                                    try {

                                                threadTransaction.set(null);

                                                if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {

                                                            log

                                                                                    .debug("Tyring to rollback database transaction of this thread.");

                                                            tx.rollback();

                                                            log.debug("Database transaction rolled back.");

                                                }

                                    } catch (RuntimeException ex) {

                                                throw new RuntimeException(

                                                                        "Might swallow original cause, check ERROR log!", ex);

                                    } finally {

                                                closeSession();

                                    }

                        } else {

                                    log

                                                            .warn("Using CMT/JTA, intercepted superfluous tx rollback call.");

                        }

            }

 

            /**

             * Reconnects a Hibernate Session to the current Thread.

             * <p>

             * Unsupported in a CMT environment.

             *

             * @param session

             *            The Hibernate Session to be reconnected.

             */

            public static void reconnect(Session session) {

                        if (useThreadLocal) {

                                    log.debug("Reconnecting Session to this thread.");

                                    session.reconnect();

                                    threadSession.set(session);

                        } else {

                                    log

                                                            .error("Using CMT/JTA, intercepted not supported reconnect call.");

                        }

            }

 

            /**

             * Disconnect and return Session from current Thread.

             *

             * @return Session the disconnected Session

             */

            public static Session disconnectSession() {

                        if (useThreadLocal) {

                                    Transaction tx = (Transaction) threadTransaction.get();

                                    if (tx != null && (!tx.wasCommitted() || !tx.wasRolledBack()))

                                                throw new IllegalStateException(

                                                                        "Disconnecting Session but Transaction still open!");

                                    Session session = getCurrentSession();

                                    threadSession.set(null);

                                    if (session.isConnected() && session.isOpen()) {

                                                log.debug("Disconnecting Session from this thread.");

                                                session.disconnect();

                                    }

                                    return session;

                        } else {

                                    log

                                                            .error("Using CMT/JTA, intercepted not supported disconnect call.");

                                    return null;

                        }

            }

 

            /**

             * Register a Hibernate interceptor with the current SessionFactory.

             * <p>

             * Every Session opened is opened with this interceptor after registration.

             * Has no effect if the current Session of the thread is already open,

             * effective on next close()/getCurrentSession().

             * <p>

             * Attention: This method effectively restarts Hibernate. If you need an

             * interceptor active on static startup of HibernateUtil, set the

             * <tt>hibernateutil.interceptor</tt> system property to its fully

             * qualified class name.

             */

            public static void registerInterceptorAndRebuild(Interceptor interceptor) {

                        log.debug("Setting new global Hibernate interceptor and restarting.");

                        configuration.setInterceptor(interceptor);

                        rebuildSessionFactory();

            }

 

            public static Interceptor getInterceptor() {

                        return configuration.getInterceptor();

            }

}

 

大家可以从lin_bei的文章中得到这个类的详细说明,在这里我就不多说了。

总结:

AutoTest这个项目是我第一次写正式的DAO和第一次使用Hibernate,现在phase I的开发工作马上就要完成了,在这里我要给出我的一些小建议:

1 尽早的建立junitTest

大家可能发现了,小茵茵在开发过程中已经refactor了一次,而且由于这个项目被分成了若干个component,所以整个project的配置也经常发生变化,很容易会出现很多问题。但是要感谢junit,在每update项目或者commit我自己的代码之前,我都会跑一次junit Tests,这样能够很容易发现问题。而且在后期的集成工作中,当其他component调用我的接口出现问题时,我可以用junit很简单的检测出是否是我的代码内部有问题还是他们调用的时候出现了差错

另一个好处就是junit可以个别的开发人员一个使用的范例,大家照着我的junit case写他们的logic就避免了很多问题

 

2 合理的使用抽象

CommonDAO的建立使我省去了不少开发时间,而且使之后的维护工作变的更加顺利。现在事务的封装都是在CommonDAO完成,也许今后我会开放事务操作的接口,让business logic来进行事务的管理,这样就能灵活的保证多个操作在同一事务中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值