Spring4-3-使用JdbcTemplate和事务处理

一.使用JdbcTemplate操作数据库

  • 创建db.properties配置文件
jdbc.user=common
jdbc.password=common
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///db_spring

jdbc.initPoolSize=5
jdbc.maxPoolSize=10
  • 配置Spring配置文件applicationContext.xml
    <!-- 使用jdbc配置 -->
    
     <!-- 导入属性文件 classpath代表类路径 -->
    <context:property-placeholder location="classpath:db.properties"/> 
    <!--  配置c3p0数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
       <!-- 使用外部属性文件的属性 -->
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        
        <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
        <property name="maxPoolSize"  value="${jdbc.maxPoolSize}"></property>
    </bean>
    
    <!-- 配置Spring jdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 扫描带注解的bean,使用注解方式加载bean -->
    <context:component-scan base-package="lxf.spring.jdbc.dao"></context:component-scan>
  • 单元测试JDBCTest.java
package lxf.spring.jdbc;
/**
 * 测试jdbc操作
 * @author lxf
 */
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.sql.DataSource;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import lxf.spring.jdbc.bean.Goods;
import lxf.spring.jdbc.dao.GoodsDao;

public class JDBCTest {
    private ApplicationContext  ctx= null;
    private JdbcTemplate jdbcTemplate;
    {
        ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");
    }
    /**
     * 获取单个列值,或做统计查询
     */
    @Test
    public void testQueryTotal()
    {
        String sql = "SELECT COUNT(goods_id) FROM goods";
        long count = jdbcTemplate.queryForObject(sql,long.class);
        System.out.println(count);
    }
    /**
     * 查到实体类的集合
     */
    @Test
    public void testQueryForList()
    {
        String sql = "SELECT * FROM goods WHERE goods_id > ?";
        RowMapper<Goods> rowMapper = new BeanPropertyRowMapper<>(Goods.class);
        List<Goods> goods = jdbcTemplate.query(sql, rowMapper,1);
        System.out.println(goods);      
        
    }   
    /**
     * 从数据库获取一条记录,实际得到对应的对象
     */
    @Test
    public void testQueryForObject()
    {
        String sql = "SELECT *  FROM  goods WHERE goods_id = ?";
        RowMapper<Goods> rowMapper = new BeanPropertyRowMapper<>(Goods.class);
        Goods goods = jdbcTemplate.queryForObject(sql, rowMapper,1);
        System.out.println(goods);      
    }
    
    /**
     * 执行批量更新,批量insert update delete
     */
    @Test
    public void testBatchUpate()
    {
        String sql = "INSERT INTO goods (goods_name,cost_price,selling_price,manufactuer) VALUES (?,?,?,?)";
        List<Object[]> batchArgs = new ArrayList<Object[]>();
        batchArgs.add(new Object[]{"AA","100","101","shanghai"});
        batchArgs.add(new Object[]{"BB","200","201","beijing"});
        batchArgs.add(new Object[]{"CC","300","301","guangzhou"});
        int[] res = jdbcTemplate.batchUpdate(sql,batchArgs);
        System.out.println(Arrays.asList(res));
    }
    /**
     * 修改数据
     */
    @Test
    public void testUpdate()
    {
        String sql = "UPDATE goods SET goods_name = ? WHERE goods_id = ?";
        jdbcTemplate.update(sql,"aaa",1);
    }   
    /**
     * 测试获取数据库连接
     */
    @Test
    public void testDataSource()
    {
        DataSource dataSource = (DataSource) ctx.getBean("dataSource");
        try {
            System.out.println(dataSource.getConnection());
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    /**
     * 单元测试dao层查询单条记录
     */
    @Test
    public void testGetOne()
    {
        GoodsDao gD = (GoodsDao) ctx.getBean("goodsDao");
        Goods goodsOne = gD.getOne(1);
        System.out.println(goodsOne);
    }
}
  • GoodsDao的编写
package lxf.spring.jdbc.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

import lxf.spring.jdbc.bean.Goods;
/**
 * GoodsDao操作数据库
 * @author lxf
 *
 */
@Repository
public class GoodsDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    /**
     * 根据主键获取goods表单条记录
     * @param id
     * @return
     */
    public Goods getOne(Integer id)
    {
        String sql = "SELECT *  FROM  goods WHERE goods_id = ?";
        RowMapper<Goods> rowMapper = new BeanPropertyRowMapper<>(Goods.class);
        Goods goods=null;
        try {
            goods = jdbcTemplate.queryForObject(sql, rowMapper,id);
        } catch (DataAccessException e) {
            e.printStackTrace();
        }
        return goods;
    }
}

二.使用Jdbc具名参数模板NamedParameterJdbcTemplate操作数据库

  • 原来的jdbc在sql语句中预加载的是?,后续需要对应位置;
  • 而具名参数就是将预加载的 ?参数名称 代替
    具体使用方式如下:
    (1)在Spring配置文件中配置NamedParameterJdbcTemplate的Bean
    <!-- 配置NamedParameterJdbcTemplate,该对象可以使用具名参数,其没有无参构造器,只有含有参构造器 -->
    <bean id="namedParameterJdbcTemplate" 
            class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
            <constructor-arg  ref="dataSource"></constructor-arg>      
      </bean>

(2)使用:

    private JdbcTemplate jdbcTemplate;
    //具名参数jdbcTemplate
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    {
        ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");
        namedParameterJdbcTemplate = ctx.getBean(NamedParameterJdbcTemplate.class);
    }
    /**
     * 使用具名参数时,可以使用update(String sql, SqlParameterSource paramSource)方法进行更新操作
     * 1.SQL语句中的参数名和类的属性名保持一致
     * 2.使用SqlParameterSource接口的实现类BeanPropertySqlParameterSource作为参数
     */
    @Test
    public void testNameParamJdbc2()
    {
        String sql = "INSERT INTO goods  (goods_name,cost_price,selling_price,manufactuer) " + 
                            "VALUES (:goods_name,:cost_price,:selling_price,:manufactuer)";
        Goods goods = new Goods();
        goods.setGoods_name("耐克运动鞋");
        goods.setCost_price(800);
        goods.setSelling_price(699);
        goods.setManufactuer("产地山东");
        SqlParameterSource paramSource = new BeanPropertySqlParameterSource(goods);
        int res = namedParameterJdbcTemplate.update(sql, paramSource);
        System.out.println(res);
    }
    
    /**
     * 测试jdbc具名参数的新增数据库操作
     * 好处:若有多个参数则不用在去对应位置,直接对应参数名,便于维护
     */
    @Test
    public void testNameParamJdbc()
    {
        String sql = "INSERT INTO goods  (goods_name,cost_price,selling_price,manufactuer) VALUES (:gname,:cprice,:sprice,:manf)";
        Map<String,Object> paramMap = new HashMap<String,Object>();
        paramMap.put("gname", "阿迪达斯运动鞋");
        paramMap.put("cprice", "500");
        paramMap.put("sprice", "459");
        paramMap.put("manf", "产地河北");
        int res = namedParameterJdbcTemplate.update(sql, paramMap);
        System.out.println(res);
    }

三,事务(使用注解的方式配置事务)

Paste_Image.png
Paste_Image.png
  • Spring配置文件配置
      <!-- 配置事务管理器 -->
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
      </bean>
      <!-- 启用事务注解 ,注意:需要先启用tx命名空间-->
      <tx:annotation-driven transaction-manager="transactionManager"/>
  • 在需要加事务的业务逻辑方法上加注解:@Transactional
package lxf.spring.tx;
import javax.management.RuntimeErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class BookShopServiceImpl {
    
    @Autowired
    private BookShopDao bookShopDao;
    /**
     * 用户买书方法
     * @param userId 用户账户表account表主键
     * @param bookId   书books表主键
     */
    //添加事务注解,只在在执行的方法中执行多个业务罗辑之间有一个抛出异常则会执行事务
    //如果有异常但是不抛出,则事务不起作用
    @Transactional
    public void buyBook  (int userId, int bookId) 
    {
        //1.获取对应数的单价
        double price = bookShopDao.findBookPriceBookId(bookId);
        //2.减库存
        try {
            bookShopDao.updateBookStock(bookId);
        } catch (Error e1) {
            System.out.println("book stock error");
            //e1.printStackTrace();
            throw new RuntimeException(e1);
        }
        //3.扣除用户账户余额
        try {
            bookShopDao.updateUserAccount(userId, price);
        } catch (AccountException e) {
            throw new RuntimeException(e);
        }
    }
}

BookShopDao

package lxf.spring.tx;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
 * 书店dao
 * @author lxf
 */
@Repository("bookShopDao")
public class BookShopDaoImpl implements BookShopDao {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public double findBookPriceBookId(Integer bookId) {
        String sql = "SELECT price from books WHERE book_id = ?";
        return jdbcTemplate.queryForObject(sql, double.class, bookId);
    }

    @Override
    public void updateBookStock(Integer bookId) {
        String sql1 = "SELECT stock from book_stock WHERE book_id= ?";
        double stock = jdbcTemplate.queryForObject(sql1, double.class, bookId);
        //如果库存不足则抛出异常
        if(stock<=0)
        {
            throw new BookStockException("图书库存不足");
        }      
       String sql = "UPDATE book_stock SET stock = stock-1 WHERE book_id = ?";
       jdbcTemplate.update(sql, bookId);
    }

    @Override
    public void updateUserAccount(Integer userId, double price) {
        String sql1 = "SELECT balance from acount WHERE id= ?";
        int balance = jdbcTemplate.queryForObject(sql1, Integer.class, userId);
        //如果用户余额不足则抛出异常
        if(balance<=0)
        {
            throw new AccountException("用户余额不足!");
        }
        String sql = "UPDATE acount SET balance=balance-? WHERE id = ?";
        jdbcTemplate.update(sql, price, userId);
    }
}
  • 用户余额不足异常定义
package lxf.spring.tx;
/**
 * 用户余额不足异常
 * @author lxf
 */
public class AccountException extends RuntimeException{
    public AccountException() {
        super();
        // TODO Auto-generated constructor stub
    }

    public AccountException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
        // TODO Auto-generated constructor stub
    }

    public AccountException(String message, Throwable cause) {
        super(message, cause);
        // TODO Auto-generated constructor stub
    }

    public AccountException(String message) {
        super(message);
        // TODO Auto-generated constructor stub
    }

    public AccountException(Throwable cause) {
        super(cause);
        // TODO Auto-generated constructor stub
    }  
}

四.事务传播行为

Paste_Image.png

五.Spring事务传播行为

Paste_Image.png
Paste_Image.png

六.REQUIED默认的传播行为

  • Tom用户的钱只够买一本书,当A用户选择两本书购买的时候,因为第二本书钱不够了,所以 两本书都没有买成功
    Paste_Image.png

七.REQUIRED_NEW传播行为

  • Tom用户的钱只够买一本书,当A用户选择两本书购买的时候,第一本书的事务提交,账户钱成功扣除,库存成功-1; 第二本书因为钱不够事务回滚,账户钱和库存均不变;(第一本买成功,第二本没买成功
    Paste_Image.png

八.事务传播行为代码实现

(1)以上代码BookShopServiceImpl修改

@Service
public class BookShopServiceImpl {
    
    @Autowired
    private BookShopDao bookShopDao;
    /**
     * 用户买书方法
     * @param userId 用户账户表account表主键
     * @param bookId   书books表主键
     */
    /**
     * 添加事务注解,只在在执行的方法中执行多个业务罗辑之间有一个抛出异常则会执行事务
     * 如果有异常但是不抛出,则事务不起作用
     * 使用propagation指定事务的传播行为,即当前的事务方法被另外一个事务方法调用时
     * 如何使用事务,默认取值为REQUIRED,即使用调用方法的事务
     * REQUIRED_NEW:事务自己的事务,调用的事务方法的事务被挂起;
     */
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void buyBook  (int userId, int bookId) 
    {
        //1.获取对应数的单价
        double price = bookShopDao.findBookPriceBookId(bookId);
        //2.减库存
        try {
            bookShopDao.updateBookStock(bookId);
        } catch (Error e1) {
            System.out.println("book stock error");
            //e1.printStackTrace();
            throw new RuntimeException(e1);
        }
        //3.扣除用户账户余额
        try {
            bookShopDao.updateUserAccount(userId, price);
        } catch (AccountException e) {
            throw new RuntimeException(e);
        }
    }
}

(2)新增收银台接口负责处理用户同事买多本书的桂芬

package lxf.spring.tx;
import java.util.List;

/**
 * 收银台接口
 * @author lxf
 */
public interface Cashier { 
    public void checkout(int userId, List<Integer>booksID);
}

(3)Cashier收银台实现类CashierImpl

package lxf.spring.tx;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
 * 收银台实现类,测试事务的传播行为
 * @author lxf
 */
@Service("cashier")
public class CashierImpl implements Cashier {
    @Autowired
    private BookShopServiceImpl bookShopServiceImpl;
    /**
     * 一个用户买多本书的情况,新增事务
     */
    @Transactional
    @Override
    public void checkout(int userId, List<Integer> booksID) {
        for (Integer bookId : booksID) {
            bookShopServiceImpl.buyBook(userId, bookId);
        }
    }
}

(4)单元测试

ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
 cashier = (Cashier)ctx.getBean("cashier");
    /**
     * 单元测试事务传播行为
     */
    @Test
    public void testTransChuanbo()
    {
        int userId= 1;
        List<Integer> booksID = Arrays.asList(1,2);
        cashier.checkout(userId, booksID);
    }

事务属性说明

    /**
     * 添加事务注解,只在在执行的方法中执行多个业务罗辑之间有一个抛出异常则会执行事务
     * 如果有异常但是不抛出,则事务不起作用
     * 1.使用propagation指定事务的传播行为,即当前的事务方法被另外一个事务方法调用时
     *     如何使用事务,默认取值为REQUIRED,即使用调用方法的事务
     *     REQUIRED_NEW:事务自己的事务,调用的事务方法的事务被挂起;
     * 2.指定事务的隔离级别属性,最常用的取值是:isolation=Isolation.READ_COMMITTED
     * 3.默认情况下Spring的声明事务对所有的运行时异常进行回滚,
     *        也可以通过对应的属性进行设置,通常情况下取默认值即可,
     *        比如:指定发生AccountException异常不回滚,noRollbackFor={AccountException.class}
     * 4.使用readOnly指定事务是否是可读,若只读取数据库的方法,
     *         应设置readOnly=true,可以帮助数据库引擎优化事务.
     * 5.使用timeout属性指定强制回滚之间事务可以占用的时间,单位为:秒
     */
    @Transactional(propagation=Propagation.REQUIRES_NEW,
                                isolation=Isolation.READ_COMMITTED,
                                readOnly=false,
                                timeout=5)

九.使用xml配置文件配置事务 applicationContext-xmlconfig-tx.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
    <!-- 使用xml配置文件的方式使用事务-->
    
     <!-- 导入属性文件 classpath代表类路径 -->
    <context:property-placeholder location="classpath:db.properties"/> 
    <!--  配置c3p0数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
       <!-- 使用外部属性文件的属性 -->
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        
        <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
        <property name="maxPoolSize"  value="${jdbc.maxPoolSize}"></property>
    </bean>
    
    <!-- 配置Spring jdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
     <!-- 配置bean -->
     <bean id="bookShopDao" class="lxf.spring.tx.xmlconfig.BookShopDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
     </bean>
     <bean id="bookShopService"  class="lxf.spring.tx.xmlconfig.service.impl.BookShopServiceImpl">
        <property name="bookShopDao" ref="bookShopDao"></property>
     </bean>
     <bean id="cashier" class="lxf.spring.tx.xmlconfig.service.impl.CashierImpl">
        <property name="bookShopServiceImpl" ref="bookShopService"></property>
     </bean>
      
      <!--1. 配置事务管理器 -->
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
      </bean>
      <!-- 2.配置事务属性 -->
      <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--根据方法名指定事务的属性-->
            <tx:method name="buyBook" propagation="REQUIRED"/>
            <tx:method name="get*" read-only="false"/>
        </tx:attributes>
      </tx:advice>
      <!-- 3.配置切入点,以及把事务切入点和事务属性关联起来 -->
      <aop:config>
        <!-- 配置切入点 -->
        <aop:pointcut expression="execution( * lxf.spring.tx.xmlconfig.service.impl.BookShopServiceImpl.*(..))" id="txPointCut"/>
        <!-- 将切入点和属性关联 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config> 
</beans>

十, 手动回滚

  • 在需要回滚的地方使用如下代码:
     TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    
  • 或先设置回滚点
    Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint(); 
    
    然后回滚到具体回滚点
    //回滚到savePoint。
    TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
    
  • 参考文章

代码演示点击

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,747评论 6 342
  • 很多人喜欢这篇文章,特此同步过来 由浅入深谈论spring事务 前言 这篇其实也要归纳到《常识》系列中,但这重点又...
    码农戏码阅读 4,705评论 2 59
  • 蘑菇牛肉石锅拌饭 休木的芒椰汁 港式茶餐厅的净云吞和干炒牛河 广式叉烧肉 好多不爱吃的东西,一旦发现好吃,简直能天...
    绿玉阅读 285评论 0 1
  • 导读:你真的知道什么叫“工作到位”吗?汇报工作说结果,结果思维是第一思维;请示工作说方案,不要让老板做问答题;做工...
    城南瓦匠阅读 738评论 0 0