Spring JdbcTemplate使用和错误排查 以及整合Junit4

Spring中使用JdbcTemplate进行查询,并整合Junit4进行测试

首先,在数据库中创建表

选用的数据库是MySQL数据库,在数据库中创建一个student表。
建表语句如下:

create table student(
id int not null primary key auto_increment,
name varchar(20) not null,
age int not null
);

初始的时候在表中添加一些数据

insert into student(name,age)
values
("小李子",18),
("关小羽",15),
("盖伦",33);

现在,表和表中的数据已经有了,接下来就是代码的编写。

搭建项目环境

先预览一下程序结构。
Spring JdbcTemplate使用和错误排查 以及整合Junit4_第1张图片

导入jar包

首先是spring的核心包4个,在这里程序中使用项目构建工具maven来管理依赖。
在这里插入图片描述
接下来是使用spring的jdbc包进行数据库的操作,以及test包为了整合Junit。当然,既然要用到junit,那么也必须添加进来。
最后是MySQL数据库的驱动。
至此,一共是8个jar包。但是,由于maven会在引入一个jar包的同时,帮助你导入一些相关的依赖,所以最后的数量会大于8个。

编写Domian类

根据ORM思想,数据库中的一个表对应了Java的一个类,表中的一行记录对应了类的一个实例。这里创建了StudentDO类

/**
 * 根据orm思想对应数据库中的student表
 */
public class StudentDO {
    private int id;
    private String name;
    private int age;

    public StudentDO() {
    }

    public StudentDO(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public StudentDO(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "UserDO{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

这里提供了三个构造器,虽然只用到了两个,但是还是要说一下三个构造器的用途。空参构造器,是为了方便进行反射然后通过反射赋值;两个参数的构造器一般作为参数传入,因为student表的id字段是自增的,所以不需要额外设置;三个参数的构造器一般是作为查询方法的返回结果返回的。

编写Dao层

Dao包下的类中的方法都是直接操作数据库的。根据面向接口的原则,先定义一个StudentDao接口,接口中包含了对student表操作的几个方法,方法要实现的功能见下面代码中方法前的注释。

public interface StudentDao {
    /**
     * 查询表中学生的数量
     * @return
     */
    int getStudentNumbers();

    /**
     * 根据id查询对应的学生
     * @param id
     * @return
     */
    StudentDO queryStudentById(int id);

    /**
     * 返回所有的学生列表
     * @return
     */
    List getAllStudents();

    /**
     * 在表中增加一个学生记录
     * @param student
     */
    void addStudent(StudentDO student);

    /**
     * 在表中修改一条学生记录
     * @param id
     */
    void updateStudent(StudentDO student, int id);

    /**
     * 根据id删除学生记录
     * @param id
     */
    void deleteStudent(int id);
}

接下来是对该接口的实现,具体的实现类的是StudentDaoImpl类,类中组合了一个JdbcTemplate的引用,通过spring的di注入进去。
public class StudentDaoImpl implements StudentDao {

    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public int getStudentNumbers() {
        String sql = "select count(*) from student";
        Integer num = jdbcTemplate.queryForObject(sql, Integer.class);
        return num;
    }

    @Override
    public StudentDO queryStudentById(int id) {
        String sql = "select * from student where id = ?";
        return jdbcTemplate.queryForObject(sql, new Object[]{id}, new BeanPropertyRowMapper(StudentDO.class));
    }

    @Override
    public List getAllStudents() {
        String sql = "select * from student";
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper(StudentDO.class));
    }

    @Override
    public void addStudent(StudentDO student) {
        String sql = "insert into student(name, age) values(?, ?)";
        jdbcTemplate.update(sql, student.getName(), student.getAge());
    }

    @Override
    public void updateStudent(StudentDO student, int id) {
        String sql = "update student set name = ?, age = ? where id = ?";
        jdbcTemplate.update(sql, student.getName(), student.getAge(), student.getId());
    }

    @Override
    public void deleteStudent(int id) {
        String sql = "delete from student where id = ?";
        jdbcTemplate.update(sql, id);
    }
}

这里有几点要说明一下。

  1. 对于聚集函数的查询,体现在类中的第一个getStudentNumbers,返回值是int。对于Spring3来说,提供了一个queryForInt的方法,但是编写程序的时候一直提示不出来。最后,发现该方法已经被移除了,如果查询的结果是基本数据类型,可以使用我在程序中用的queryForObject(String sql,Class clazz)。
  2. 查询返回一个对象,一开始看JdbcTemplate的方法,觉得刚才那个方法既然能查基本数据类型了,那么复杂数据类型也能查吧,发现不行。看了一下代码实现,该方法底层调用的是queryForObject(String sql, getSingleColumnRowMapper(Class clazz))。果然,原来底层帮我new了一个映射器,而且是个单列映射器,也就是说,它只能查询返回一行一列的结果。最后,将方法改成queryForObject(String sql, Object… args, RowMapper rowmapper)。另外,这里的RowMapper最好使用BeanPropertyMapper。
  3. 查询返回列表,情况与2相同,不要使用queryForList方法,而是使用query(sql, rowmapper)。

编写xml配置文件

使用jdbcTemplate,那么一定要设置连接池DataSource,这里连接池的选用使用的是spring-jdbc包里自带的DriverManagerDataSource。对于常用的三种连接池c3p0、dbcp、Druid,推荐使用Druid。c3p0稳定但是性能不好,dbcp稳定性不是很高,Druid综合了前两个的优点,并且可以进行sql优化和性能调优。
具体配置如下:

Spring JdbcTemplate使用和错误排查 以及整合Junit4_第2张图片
这里对于连接池的参数使用了一个properties文件,然后将properties文件放入spring容器中。
注意:这里读取properties文件的配置使用了context的命名空间,需要在xml的schema中添加context的命名空间。



整合junit进行测试

// 下面两个注解自动加载配置文件并加载测试环境,再将类中属性自动注入
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:jdbc.xml")
public class JdbcTemplateTest {

    @Autowired
    private StudentDaoImpl studentDao;

    @Test
    public void testJdbcTemplate() {
       int num = studentDao.getStudentNumbers();
        System.out.println("当前有" + num + "个学生");
        System.out.println("--------");
        System.out.println("学生的详细信息");
        List allStu = studentDao.getAllStudents();
        allStu.forEach(System.out::println);
        System.out.println("--------");
        StudentDO studentDO = new StudentDO("大司马", 43);
        studentDao.addStudent(studentDO);
        StudentDO student = studentDao.queryStudentById(4);
        System.out.println("新加的学生" + student);
        System.out.println("-------");
        student.setAge(17);
        studentDao.updateStudent(student, 4);
        student = studentDao.queryStudentById(4);
        System.out.println("修改年龄后" + student);
        studentDao.deleteStudent(4);
        System.out.println("--------");
        System.out.println("学生的详细信息");
        allStu = studentDao.getAllStudents();
        allStu.forEach(System.out::println);
    }
}

测试结果:


结合Junit需要spring-test包,在测试类上添加@Runwith(SpringJunit4ClassRunner.class),这是表明该类进行测试的时候自动加载测试环境,@ContextConfiguration(locations=“classpath:xml的路径”),加载配置文件,对类中自动注入的属性进行注入。
注意:
1.Junit包要选择4.12以上的,否则运行会报错(而且报错信息提示你要使用Junit4.12或以上的版本)
2.locations属性的值要添加classpath,因为tomcat的路径和项目路径是不一样的,项目发布时会报找不到文件异常。另外,idea默认的classpath是target/classes目录下,所以要设置resources目录并标记为资源文件夹,这样才会在编译时将其放入classpath路径下。

最好,对于上面的程序,只是一个小demo,熟悉一下JdbcTemplate的使用。
实际上,StudentDaoImpl可以继承JdbcDaoSupport类,该类可以直接注入DataSource,在类中自动newJdbcTemplate实例,通过getJdbcTemplate()获得该实例。

你可能感兴趣的:(Spring,Spring,JdbcTemplate,Junit,数据库,mysql)