SpringBoot系列(入门,ORM,Transaction,lOG)

今天写篇springboot的博客,主要介绍一下springboot搭建以及一些整合。

首先介绍springboot搭建,我今天选择Maven,想用Gradle搭建的就自己百度一下吧,访问“http://start.spring.io/”官网。

填写好Maven的GroupId以及ArtifactId然后Generate Project。

我这次使用的是IntellIj IDEA,导入generate出来的project,选择maven导入,一直选next就行了(记得选一下jdk版本,我用的是1.8),eclipse的话直接import project就行了。

初始的项目结构应该就是一个普通的maven项目,只有一个配置文件就是application.properties,也是springboot整合所有东西的配置文件。

maven pom文件的依赖只需要以下:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

如果加入web模块:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

我用的版本是1.5.4

可以按照我上面的项目结构去建立resource文件夹以及package包,注意一点,test和main的根包名需要一致,否则会报错(具体报错可以自己试试)。

首先来试试最基础的helloworld。

写一个跟SpringMVC类似的controller就可以试试helloworld了,在包的根路径建立一个Application类作为程序入口(springboot的规矩),也可以直接运行main方法启动springboot,相当于内嵌了tomcat。

运行起来之后就可以在localhost:8080/hello看到映射结果了。

如果使用Test访问:

Mock一下,然后引入

import static org.hamcrest.Matchers.equalTo;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

具体代码不解释了,看一看能猜出来。

然后来看一下普通restful风格的controller咋写,通俗点说就是我咋用springboot实现springmvc一样的东东
package com.zhengyu.web;

import com.zhengyu.model.User;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by niezy on 2017/7/26.
 */
@RestController
@RequestMapping(value = "/users") // 通过这里配置使下面的映射都在/users下
public class UserController {

  // 创建线程安全的Map
  static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long, User>());

  @RequestMapping(value = "/", method = RequestMethod.GET)
  public List<User> getUserList() {
    // 处理"/users/"的GET请求,用来获取用户列表
    // 还可以通过@RequestParam从页面中传递参数来进行查询条件或者翻页信息的传递
    List<User> r = new ArrayList<User>(users.values());
    return r;
  }

  @RequestMapping(value = "/", method = RequestMethod.POST)
  public String postUser(@ModelAttribute User user) {
    // 处理"/users/"的POST请求,用来创建User
    // 除了@ModelAttribute绑定参数之外,还可以通过@RequestParam从页面中传递参数
    users.put(user.getId(), user);
    return "success";
  }

  @RequestMapping(value = "/{id}", method = RequestMethod.GET)
  public User getUser(@PathVariable Long id) {
    // 处理"/users/{id}"的GET请求,用来获取url中id值的User信息
    // url中的id可通过@PathVariable绑定到函数的参数中
    return users.get(id);
  }

  @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
  public String putUser(@PathVariable Long id, @ModelAttribute User user) {
    // 处理"/users/{id}"的PUT请求,用来更新User信息
    User u = users.get(id);
    u.setName(user.getName());
    u.setAge(user.getAge());
    users.put(id, u);
    return "success";
  }

  @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
  public String deleteUser(@PathVariable Long id) {
    // 处理"/users/{id}"的DELETE请求,用来删除User
    users.remove(id);
    return "success";
  }

}

一样的controller如上图,然后开始测试呗

package com.zhengyu;

import com.zhengyu.web.UserController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class ApplicationTests {

  private MockMvc mvc;

  @Before
  public void setUp() throws Exception {
    mvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
  }

  @Test
  public void testUserController() throws Exception {
    // 测试UserController
    RequestBuilder request = null;

    // 1、get查一下user列表,应该为空
    request = MockMvcRequestBuilders.get("/users/");
    mvc.perform(request).andExpect(status().isOk()).andExpect(content().string(equalTo("[]")));

    // 2、post提交一个user
    request = post("/users/").param("id", "1").param("name", "测试大师").param("age", "20");
    mvc.perform(request).andExpect(content().string(equalTo("success")));

    // 3、get获取user列表,应该有刚才插入的数据
    request = MockMvcRequestBuilders.get("/users/");
    mvc.perform(request).andExpect(status().isOk())
        .andExpect(content().string(equalTo("[{\"id\":1,\"name\":\"测试大师\",\"age\":20}]")));

    // 4、put修改id为1的user
    request = put("/users/1").param("name", "测试终极大师").param("age", "30");
    mvc.perform(request).andExpect(content().string(equalTo("success")));

    // 5、get一个id为1的user
    request = MockMvcRequestBuilders.get("/users/1");
    mvc.perform(request).andExpect(content().string(equalTo("{\"id\":1,\"name\":\"测试终极大师\",\"age\":30}")));

    // 6、del删除id为1的user
    request = delete("/users/1");
    mvc.perform(request).andExpect(content().string(equalTo("success")));

    // 7、get查一下user列表,应该为空
    request = MockMvcRequestBuilders.get("/users/");
    mvc.perform(request).andExpect(status().isOk()).andExpect(content().string(equalTo("[]")));

  }

}

好咯~


下面说一下log,spring1.5.4版本是不支持log4j老用法了,我查了一下然后选择的是log4j2xml的方式,pom如下:
<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter</artifactId>    <exclusions>        <exclusion>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-logging</artifactId>        </exclusion>    </exclusions></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-log4j2</artifactId></dependency>

首先springboot自带的是logback,我们首先更改之前的pom,加上
 <exclusions>        <exclusion>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-logging</artifactId>        </exclusion>    </exclusions>
除去logback,然后引入log4j2.然后在resource文件夹底下新建一个log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="WARN" monitorInterval="30">
    <!--先定义所有的appender-->
    <appenders>
        <!--这个输出控制台的配置-->
        <console name="Console" target="SYSTEM_OUT">
            <!--输出日志的格式-->
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
        </console>
        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用-->
        <File name="log" fileName="log/test.log" append="false">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
        </File>
        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileInfo" fileName="${sys:user.home}/logs/info.log"
                     filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>
        <RollingFile name="RollingFileWarn" fileName="${sys:user.home}/logs/warn.log"
                     filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>
        <RollingFile name="RollingFileError" fileName="${sys:user.home}/logs/error.log"
                     filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <loggers>
        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
        <logger name="org.springframework" level="INFO"></logger>
        <logger name="org.mybatis" level="INFO"></logger>
        <root level="all">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
        </root>
    </loggers>
</configuration>

  然后在application.properties配置文件里加上

logging.config=classpath:log4j2.xml 其实不加也行,起码我测试这个版本没问题,随便你啦,强迫症的加上吧。

下面说说spring jdbcTemplate
<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-jdbc</artifactId>    <version>1.5.2.RELEASE</version></dependency><dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <version>5.1.21</version></dependency>

加上这个依赖,然后我们开始codeing

建个user类

application.properties加上:

spring.datasource.url=jdbc:mysql://localhost:3306/bootspring.datasource.username=rootspring.datasource.password=rootspring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.jpa.properties.hibernate.hbm2ddl.auto=create-droplog4j.logger.org.springframework.jdbc.core=DEBUG, filelog4j.logger.org.springframework.jdbc.core.StatementCreatorUtils=TRACE, file

然后建一个UserService,跟springmvc没什么两样
/**
 * Created by niezy on 2017/7/26.
 */
public interface UserService {
  /**
   * 新增一个用户
   *
   * @param name
   * @param age
   */
  void create(String name, Integer age);

  /**
   * 根据name删除一个用户高
   *
   * @param name
   */
  void deleteByName(String name);

  /**
   * 获取用户总量
   */
  Integer getAllUsers();

  /**
   * 删除所有用户
   */
  void deleteAllUsers();

  /**
   * 根据姓名更新年龄
   * @param name
   * @param age
   */
  void update(String name,int age);

  /**
   * 根据姓名查对象
   * @param name
   * @return
   */
  User querySingleUser(String name);

}
/**
 * Created by niezy on 2017/7/26.
 */
@Service
public class UserServiceImpl implements UserService {
  @Autowired
  private JdbcTemplate jdbcTemplate;

  @Override
  public void create(String name, Integer age) {
    jdbcTemplate.update("insert into USER(NAME, AGE) values(?, ?)", name, age);
  }

  @Override
  public void deleteByName(String name) {
    jdbcTemplate.update("delete from USER where NAME = ?", name);
  }

  @Override
  public Integer getAllUsers() {
    return jdbcTemplate.queryForObject("select count(1) from USER", Integer.class);
  }

  @Override
  public void deleteAllUsers() {
    jdbcTemplate.update("delete from USER");
  }

  @Override
  public void update(String name, int age) {
    jdbcTemplate.update("update user set age = ? where name=? ", age, name);
  }

  @Override
  public User querySingleUser(String name) {
    User user = new User();
    user.setName(name);
    // 返回对象需要beanPropertyRowMapper映射,查询条件放到Object数组
    return jdbcTemplate.queryForObject("select * from user where name=? ", new Object[] {name},
        new BeanPropertyRowMapper<User>(User.class));
  }
}

然后测试

package com.zhengyu;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.zhengyu.jdbcservice.UserService;

/**
 * Created by niezy on 2017/7/26.
 */

@RunWith(SpringRunner.class)
@SpringBootTest
public class JdbcApplicationTests {
  @Autowired
  private UserService userSerivce;

  @Before
  public void setUp() {
    // 准备,清空user表
    userSerivce.deleteAllUsers();
  }

  @Test
  public void test() throws Exception {
    // 插入5个用户
    userSerivce.create("zhangsan", 18);
    userSerivce.create("lisi", 19);
    userSerivce.create("wangwu", 20);
    userSerivce.create("haozi", 25);
    userSerivce.create("zhengyu", 23);
    // 查数据库,应该有5个用户
    Assert.assertEquals(5, userSerivce.getAllUsers().intValue());
    // 删除两个用户
    userSerivce.deleteByName("zhangsan");
    userSerivce.deleteByName("haozi");
    userSerivce.update("wangwu", 28);
    System.out.println(userSerivce.querySingleUser("zhengyu").toString());
    // 查数据库,应该有3个用户
    Assert.assertEquals(3, userSerivce.getAllUsers().intValue());
  }
}

自己跑一下试试  ~

jdbcTemplate只有一点注意的,返回对象稍微麻烦点,需要按他的BeanPropertyRowMapper规矩来,其实还有很多种玩法,ORM框架都有很多玩法,返回Object数组啦,集合啦,List<Map>等等,说到底都是封装的jdbc,然后有的框架是全mapping,有的是半mapping,包括Hibernate实现的JPA标准,也可以nativeSql支持数组[]选字段返回,也可以直接mapping整个类,甚至级联操作,下次专门写个博客好好说说ORM

插一点事务的东东,springboot整合jpa jdbctempalte等ORM的depency已经自带Transaction注解了,也是默认的

你可以在@Test处加上

@Transactional(propagation = Propagation.REQUIRED)

然后我们开始spring-data-jpa黑魔法,号称业务操作几乎不需要写任何sql的ORM框架,也是spring进军ORM的产品

pom:

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-jpa</artifactId>    <version>1.5.3.RELEASE</version></dependency>

<dependency>    <groupId>javax.persistence</groupId>    <artifactId>persistence-api</artifactId>    <version>1.0.2</version></dependency>

IDEA 1.5.4版本要选择一下jpa的版本,否则会有引不到JPA注解的bug,我当时就被坑了十几分钟,换了很多persistence的depency

老规矩,model开始
package com.zhengyu.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.math.BigDecimal;

/**
 * Created by niezy on 2017/7/26.
 */
@Entity
@Table(name = "student")
public class Student {
  @Id
  @GeneratedValue
  private Long id;
  @Column(nullable = false,length = 5)
  private String name;
  @Column(nullable = false)
  private Integer age;

  @Column(nullable = false)
  private BigDecimal salary;

  @Column(nullable = false)
  private String address;

  public Student() {}

  public Student(String name, Integer age) {
    this.name = name;
    this.age = age;
  }

  public Student(Long id, String name, Integer age) {
    this.id = id;
    this.name = name;
    this.age = age;
  }

  public Student(String name, Integer age, BigDecimal salary, String address) {
    this.name = name;
    this.age = age;
    this.salary = salary;
    this.address = address;
  }

  public BigDecimal getSalary() {
    return salary;
  }

  public void setSalary(BigDecimal salary) {
    this.salary = salary;
  }

  public String getAddress() {
    return address;
  }

  public void setAddress(String address) {
    this.address = address;
  }

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Integer getAge() {
    return age;
  }

  public void setAge(Integer age) {
    this.age = age;
  }

  @Override
  public String toString() {
    return "Student{" + "id=" + id + ", name=‘" + name + ‘\‘‘ + ", age=" + age + ", salary=" + salary + ", address=‘"
        + address + ‘\‘‘ + ‘}‘;
  }
}

然后service:

package com.zhengyu.datajpaservice;

import com.zhengyu.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.math.BigDecimal;
import java.util.List;

/**
 * Created by niezy on 2017/7/26.
 */
public interface StudentRepository extends JpaRepository<Student, Long> {

  Student findByName(String name);

  List<Student> findListByName(String name);

  Student findByNameAndAge(String name, Integer age);

  @Query("from Student  where name=:name")
  Student findStudent(@Param("name") String name);

  List<Student> findByNameOrderBySalaryDesc(String name);

  List<Student> findBySalary(BigDecimal salary);

}
测试:
package com.zhengyu;

import com.zhengyu.datajpaservice.StudentRepository;
import com.zhengyu.model.Student;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;

/**
 * Created by niezy on 2017/7/26.
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringdatajpaTest {
  @Autowired
  private StudentRepository studentRepository;

  // @Before
  // public void setUp() {
  // // 准备工作
  // studentRepository.deleteAll();
  //
  // }

  @Test
  @Transactional(propagation = Propagation.REQUIRED)
  public void test() throws Exception {

    // 创建10条记录
    studentRepository.save(new Student("AAA", 10, new BigDecimal(20000), "shanghai"));
    studentRepository.save(new Student("BBB", 20, new BigDecimal(50000), "beijing"));
    studentRepository.save(new Student("CCC", 30, new BigDecimal(20000), "shanghai"));
    studentRepository.save(new Student("DDD", 40, new BigDecimal(50000), "beijing"));
    studentRepository.save(new Student("EEE", 50, new BigDecimal(20000), "shanghai"));
    studentRepository.save(new Student("EEE", 60, new BigDecimal(50000), "beijing"));
    studentRepository.save(new Student("EEE", 70, new BigDecimal(20000), "shanghai"));
    studentRepository.save(new Student("FFF", 60, new BigDecimal(50000), "beijing"));
    studentRepository.save(new Student("III", 90, new BigDecimal(20000), "shanghai"));
    studentRepository.save(new Student("JJJ", 100, new BigDecimal(50000), "beijing"));

    // 测试findAll, 查询所有记录
    Assert.assertEquals(10, studentRepository.findAll().size());
    // 测试findByName, 查询姓名为FFF的User
    Assert.assertEquals(60, studentRepository.findByName("FFF").getAge().longValue());
    // 测试findUser, 查询姓名为FFF的User
    Assert.assertEquals(60, studentRepository.findStudent("FFF").getAge().longValue());
    // 测试findByNameAndAge, 查询姓名为FFF并且年龄为60的User
    Assert.assertEquals("FFF", studentRepository.findByNameAndAge("FFF", 60).getName());
    // 测试删除姓名为AAA的User
    studentRepository.delete(studentRepository.findByName("AAA"));
    // 测试findAll, 查询所有记录, 验证上面的删除是否成功
    Assert.assertEquals(9, studentRepository.findAll().size());

    // List<Student> stuList = studentRepository.findByNameOrderBySalaryDesc("EEE");
    List<Student> stuList = studentRepository.findBySalary(new BigDecimal(20000));
    for (Student stu : stuList) {
      System.out.println(stu.toString());
    }

    List<Student> stuList2 = studentRepository.findListByName("EEE");
    for (Student stu : stuList2) {
      System.out.println(stu.toString());
    }

  }
}

application.properties加上:

spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop

关于hbm2ddl:

这个属于hibernate知识点了,我这里选择create-drop。

关于spring-data-jpa,确实很轻量很给力

在实际开发过程中,对数据库的操作无非就“增删改查”。就最为普遍的单表操作而言,除了表和字段不同外,语句都是类似的,开发人员需要写大量类似而枯燥的语句来完成业务逻辑。

为了解决这些大量枯燥的数据操作语句,我们第一个想到的是使用ORM框架,比如:Hibernate。通过整合Hibernate之后,我们以操作Java实体的方式最终将数据改变映射到数据库表中。

为了解决抽象各个Java实体基本的“增删改查”操作,我们通常会以泛型的方式封装一个模板Dao来进行抽象简化,但是这样依然不是很方便,我们需要针对每个实体编写一个继承自泛型模板Dao的接口,再编写该接口的实现。虽然一些基础的数据访问已经可以得到很好的复用,但是在代码结构上针对每个实体都会有一堆Dao的接口和实现。

由于模板Dao的实现,使得这些具体实体的Dao层已经变的非常“薄”,有一些具体实体的Dao实现可能完全就是对模板Dao的简单代理,并且往往这样的实现类可能会出现在很多实体上。Spring-data-jpa的出现正可以让这样一个已经很“薄”的数据访问层变成只是一层接口的编写方式。

Spring-data-jpa的能力远不止本文提到的这些,由于本文主要以整合介绍为主,对于Spring-data-jpa的使用只是介绍了常见的使用方式。诸如@Modifying操作、分页排序、原生SQL支持以及与Spring MVC的结合使用等等内容就不在本文中详细展开





@Transactional(isolation = Isolation.DEFAULT)
时间: 2024-10-15 22:15:34

SpringBoot系列(入门,ORM,Transaction,lOG)的相关文章

Laravel 5 系列入门教程(一)【最适合中国人的 Laravel 教程】

Laravel 5 系列入门教程(一)[最适合中国人的 Laravel 教程] 分享⋅ johnlui⋅ 于 2年前 ⋅ 最后回复由 skys215于 11个月前 ⋅ 17543 阅读 原文发表在我的个人网站:Laravel 5 系列入门教程(一)[最适合中国人的 Laravel 教程] 本教程示例代码见:https://github.com/johnlui/Learn-Laravel-5 大家在任何地方卡住,最快捷的解决方式就是去看我的示例代码. Laravel 5 中文文档: http://

SpringData 基于SpringBoot快速入门

SpringData 基于SpringBoot快速入门 本章通过学习SpringData 和SpringBoot 相关知识将面向服务架构(SOA)的单点登录系统(SSO)需要的代码实现.这样可以从实战中学习两个框架的知识,又可以为单点登录系统打下基础.通过本章你将掌握 SpringBoot项目的搭建,Starter pom的使用,配置全局文件,核心注解SpringBootApplication 介绍以及单元测试 SpringBootTest注解的使用.SpringData 的入门使用,Repos

SpringBoot系列之集成Thymeleaf用法手册

目录 1.模板引擎 2.Thymeleaf简介 2.1).Thymeleaf定义 2.2).适用模板 3.重要知识点 3.1).th:text和th:utext 3.2).标准表达式 3.3).Thymeleaf遍历 3.4).公共模块抽取 3.5).行内写法介绍 3.6).Thymeleaf语法规则 4.SpringBoot集成 4.1).Springboot集成Thymeleaf简介 4.2).Thymeleaf自动配置源码简单分析 SpringBoot系列之Thymeleaf语法简单介绍

SpringBoot 系列教程之编程式事务使用姿势介绍篇

SpringBoot 系列教程之编程式事务使用姿势介绍篇 前面介绍的几篇事务的博文,主要是利用@Transactional注解的声明式使用姿势,其好处在于使用简单,侵入性低,可辨识性高(一看就知道使用了事务):然而缺点也比较明显,不够灵活,稍不注意,可能就因为姿势不对,导致事务不生效 本文将介绍另外一种事务的使用姿势,借助TransactionTemplate的编程式事务 I. 配置 本篇主要介绍的是jdbcTemplate+transactionTemplate来完成一个编程式事务的实例 de

SpringBoot 系列教程之事务不生效的几种 case

SpringBoot 系列教程之事务不生效的几种 case 前面几篇博文介绍了声明式事务@Transactional的使用姿势,只知道正确的使用姿势可能还不够,还得知道什么场景下不生效,避免采坑.本文将主要介绍让事务不生效的几种 case I. 配置 本文的 case,将使用声明式事务,首先我们创建一个 SpringBoot 项目,版本为2.2.1.RELEASE,使用 mysql 作为目标数据库,存储引擎选择Innodb,事务隔离级别为 RR 1. 项目配置 在项目pom.xml文件中,加上s

Springboot系列1_什么是Springboot

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

[转]How expensive are page splits in terms of transaction log?

How expensive are page splits in terms of transaction log? By: Paul Randal Page splits are always thought of as expensive, but just how bad are they? In this post I want to create an example to show how much more transaction log is created when a pag

The transaction log for database &#39;XXX&#39; is full due to &#39;ACTIVE_TRANSACTION&#39;.

Msg 9002, Level 17, State 4, Line 4The transaction log for database 'Test' is full due to 'ACTIVE_TRANSACTION'. 本定一个测试库错误,由于此库的LOG文件被设置成不允许自动增长,而在大量输入数据的时候报出此错.此库已经使SIMPLE恢复模式. --数据库当前LOG状态 select log_reuse_wait_desc from sys.databaseswhere name = 'T

The transaction log for database &#39;xxxx&#39; is full due to &#39;ACTIVE_TRANSACTION&#39;

今天查看Job的History,发现Job 运行失败,错误信息是:“The transaction log for database 'xxxx' is full due to 'ACTIVE_TRANSACTION'.” 错误消息表明:数据库的事务日志文件空间耗尽,log 文件不能再存储新的transaction log. SQL Server将事务日志文件在逻辑上划分为多个VLF(Virtual Log Files),将这些VLF组成一个的环形结构,以VLF为重用单元.如果一个VLF 中存在

DB2 “The transaction log for the database is full” 问题及解决办法

DB2在执行一个大的insert/update操作的时候报"The transaction log for the database is full.. "错误,查了一下文档是DB2的日志文件满了的缘故. 首先运行下面命令来查看DB2的日志配置信息 $ db2 get db cfg | grep LOG 注意其中的下面配置项 Log file size (4KB) (LOGFILSIZ) = 1024 Number of primary log files (LOGPRIMARY) =