目的:编写DAO,通过Spring中的JdbcTemplate,对数据库中的学生数据进行增删改查操作。
要操作的数据库表结构为:
一、大体框架
1.要利用JdbcTemplate,首先要添加Spring依赖。用quickstart模板创建Maven项目,在pom.xml中添加Spring依赖:
2.创建学生类(数据传递类),描述学生信息。
3.创建数据操作接口,规定需要哪些方法来操作数据。
增、改各一种方法,删、查各4中方法:通过id,name,专业+学号,Student对象(方便出现前三种方法以外的需求时删、查)。
4.创建数据操作类,实现数据操作接口
5.创建DAO工厂类,用于创建数据操作对象(日后有新的数据操作类时,只需在此修改)
6.测试类
二、通过JdbcTemplate操作数据库
为了让JdbcTemplate正常工作,只需要为其设置DataSource就可以了。
1.数据源DataSource
(1)基于Jdbc驱动的数据源
Spring提供了三个通过Jdbc驱动定义数据源的数据源类(org.springframework.jdbc.datasource.*):
DriverManagerDataSource类:每次连接请求时返回一个新的链接。
SimpleDriverDataSource类:同上,但直接使用Jdbc驱动,未解决特定环境下的类加载问题。
SingleConnectionDataSource类:每次连接请求时返回同一个链接。可以看作只有一个链接的连接池。
【这三个数据源类一般用于测试,项目上用数据源连接池是更好的选择】
配置方法:
①java程序中配置:【例】
//数据库配置存放在配置文件db.properties中
//载入db.properties
Properties sqlConfig = new Properties();
sqlConfig.load(new FileInputStream("db.properties")); //抛出IOException(FileNotFoundException)
//不抛出Exception的方法:
//sqlConfig.load(本类类名.getClassLoader().getResourceAsStream("db.properties"));
//读取db.properties中的数据
String driver = sqlConfig.getProperty("driver");
String url = sqlConfig.getProperty("url");
String username = sqlConfig.getProperty("username");
String password = sqlConfig.getProperty("password");
//配置数据源对象
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
②xml文件中配置
<context:property-placeholder location="classpath:db.properties">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${driver}"
p:url="${url}"
p:username="${username}"
p:password="${password}" />
(2)数据源连接池
Spring中并没有提供数据源连接池的实现,但我们可以利用开源实现:
Apache Commons DBCP:http://jakarta.apache.org/commons/dbcp
c3p0:http://sourceforge.net/projects/c3p0/
BoneCP:http://jolbox.com/
这些数据源的配置方法与(1)中基于jdbc的数据源类似:
①java程序中配置:【以DBCP为例】
在Maven中添加依赖后:
(前面的获取db.properties中数据的方法相同,此处不再赘述)
//配置数据源对象
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
ds.setInitialSize(5); //池配置属性
ds.setMaxActive(10);
BasicDataSource中的池配置属性:
②xml文件中配置
<context:property-placeholder location="classpath:db.properties">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${driver}"
p:url="${url}"
p:username="${username}"
p:password="${password}"
p:initialSize="5"
p:maxActive="10" />
2.创建JdbcTemplate对象(将DataSource注入到jdbcTemplate实例)
(1)java程序中完成
通过1中程序获取dataSource实例后:
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
这里的dataSource可以是javax.sql.DataSource的任意实现。
(2)xml文件完成通过Spring的依赖注入,将dataSource注入到jdbcTemplate中:
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
然后在程序中通过getBean获取这个jdbcTemplate:
ApplicationContext apc = new ClassPathXmlApplicationContext("xxx.xml");
JdbcTemplate jdbcTemplate = (JdbcTemplate) apc.getBean("jdbcTemplate");
3.使用JdbcTemplate中的方法操作数据
在调用相关函数时,将sql语句中要操作的值写为?,然后在后面加上对应的值作为参数。如果是单个值,可直接作为参数传递;如果是多个值,可以用参数数组的形式传递:new Object[]{值1,值2,...}。
比如:
要插入一个name数据,可以这样写:
jdbcTemplate.update("INSERT INTO student (name) VALUES (?)","张三");
要修改姓名和qq,可以这样写:
jdbcTemplate.update("UPDATE student SET name=?,qq=? WHERE id=?",new Object[]{"李四","123456789",45});
值得一提的是,程序中的sql语句并不需要写分号作为结尾。
JdbcTemplate中的常用方法:
- excute(sql):可以用于执行任何sql语句,一般用于执行DDL语句(数据定义语言,用于定义、修改、删除数据库/表)【返回:void】
- update(sql,Object[]):执行增删改sql语句【返回:int,影响的行数】
- batchUpdate(sql,List<Object[]>):执行批处理增删改sql语句【返回:int[],受每个语句影响的行数】
- query(sql,RowMapper<T>,Object)或(sql,Object[],RowMapper<T>):执行sql查询语句,通过RowMapper将每个行映射到一个java对象。【返回:List<T>,结果列表(映射对象)】
- queryForObject(sql,RowMapper<T>,Object)或(sql,Object[],RowMapper<T>):执行sql查询语句,通过RowMapper将单个结果映射到java对象。【返回:T,映射对象】
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
2.Spring配置
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/students?useUnicode=true&characterEncoding=UTF-8&useSSL=false
username=root
password=pass
initialSize=3
maxActive=10
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="location">
<list>
<value>classpath:db.properties</value>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<!--<context:property-placeholder location="classpath:db.properties"/>-->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:db.properties"></property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
<property name="url" value="${url}"></property>
<property name="driverClassName" value="${driver}"></property>
<property name="initialSize" value="${initialSize}"></property>
<property name="maxActive" value="${maxActive}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
3.创建Student类,用于描述学生
修改:
* 1.添加hashCode和equals方法
* 2.将构造方法获取的参数由int改为Interger,否则在Mybatis查询中,会出现“找不到类型为[String,String,Integer]的构造函数”的报错。
package cn.cage.student;
/**
* @ClassName Student
* @description 描述学生信息的类。
* @author Cage Yang
*/
public class Student implements Comparable<Student> {
private long id;
private long createTime;
private long updateTime;
private String name;
private String qq;
private String major; //学习方向
private String entryTime;
private String school;
private int jnshuId; //修真院ID
private String dailyUrl;
private String desire;
private String jnshuBro;//修真院师兄
private String knowFrom;//信息来源
/**
* @param name 学生姓名
* @param major 学习方向
* @param jnshuId 修真院ID
*/
public Student(String name, String major, Integer jnshuId) {
this.name = name;
this.major = major;
this.jnshuId = jnshuId;
}
/* (非 Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Student [name=" + name + ", major=" + major + ", jnshuId=" + jnshuId + "]";
}
/* (非 Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + jnshuId;
result = prime * result + ((major == null) ? 0 : major.hashCode());
return result;
}
/* (非 Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Student)) {
return false;
}
Student other = (Student) obj;
if (jnshuId != other.jnshuId) {
return false;
}
if (major == null) {
if (other.major != null) {
return false;
}
} else if (!major.equals(other.major)) {
return false;
}
return true;
}
/* (非 Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(Student o) {
// TODO 自动生成的方法存根
if (this.id!=o.id) { //其实相等就是指二者id都不存在(为0)的情况
return (new Long(this.id)).compareTo(new Long(o.id));
}
if (!this.major.equals(o.major)) {
return this.major.compareTo(o.major);
}
return (new Integer(this.jnshuId).compareTo(new Integer(o.jnshuId)));
}
各getter和setter...
}
4.创建数据传递接口,规定操作数据的方法
* 原因:不需要获取旧学生信息;由调用者提供id参数更好。
* 2.修改queryStuByName的返回值为List<Student>,因为可能出现的同名学生。
* 3.修改delStuByName的返回值为int,因为可能出现的同名学生。
* 4.删除delStuByName和delStuByJnshu两个方法。
* 原因:在实际业务逻辑中一般是先查询,然后根据查询结果选择删除。既然是这样,只需要根据选择项的id删除即可,不会出现误删的问题。
package cn.cage.student;
import java.util.List;
/**
* @ClassName DataOperate
* @description 数据操作接口,规定了对学生对象数据的增删改查四种操作。
* @author Cage Yang
*/
public interface StudentDAO {
//增
public abstract boolean addStu(Student stu);
//删
public abstract boolean delStuById(long id);
// public abstract int delStuByName(String name);
// public abstract boolean delStuByJnshu(String major, int jnshuId);
public abstract boolean delStu(Student stu);
//改
public abstract boolean updateStu(Student stu, long id);
//查
public abstract Student queryStuById(long id);
public abstract List<Student> queryStuByName(String name);
public abstract Student queryStuByJnshu(String major, int jnshuId);
public abstract Student queryStu(Student stu);
}
* 函数体:将返回值设为“影响行数>0则返回true”;sql语句中的条件参数由stu.getId()改为id。
* 原因:不需要获取旧学生信息;由调用者提供id参数更好。
* 2.在addStu函数中,去掉sql语句中id的添加,id由数据库自增完成,以免发生id重复的情况。
* 3.将各查询方法中的RowMapper提取出来封装为一个类,在各查询方法中直接使用此类对象,避免重复代码。
* 为适配封装的QueryStuRowMapper,将各查询方法中的sql语句改为查询所有属性。
* 4.修改addStu函数体,当name、major、jnshuId为空时报错。
* 5.在updateStu函数体中也加上非空报错。
* 6.bug:各sql语句中的表名是student,数据库表名是students,应修改。
* 7.在通过id、专业+学号查询的方法中,通过try-catch捕获EmptyResultDataAccessException异常,给出查询结果为空的提示。
* 8.修改queryStuByName的返回值为List<Student>,因为可能出现的同名学生;然后通过query函数查询,且当结果size==0时,给出查询结果为空的提示。
* 9.修改delStuByName的返回值为int,因为可能出现的同名学生。
* 10.删除delStuByName和delStuByJnshu两个方法。
* 原因:在实际业务逻辑中一般是先查询,然后根据查询结果选择删除。既然是这样,只需要根据选择项的id删除即可,不会出现误删的问题。
package cn.cage.student;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* @ClassName StudentDAOSpringImpl
* @description
* @author Cage Yang
*/
public class StudentDAOImpl implements StudentDAO {
private ApplicationContext apc = null;
private JdbcTemplate jdbcTemplate = null;
/**
* 创建对象的同时获取jdbcTemplate对象。
*/
public StudentDAOSpringImpl() {
// TODO 自动生成的构造函数存根
apc = new ClassPathXmlApplicationContext("applicationContext.xml");
jdbcTemplate = (JdbcTemplate) apc.getBean("jdbcTemplate");
}
/* (非 Javadoc)
* @see cn.cage.student.StudentDAO#addStu(cn.cage.student.Student)
*/
public boolean addStu(Student stu) {
// TODO 自动生成的方法存根
String name = stu.getName(), major = stu.getMajor();
int jnshuId = stu.getJnshuId();
if (name==null || major==null || jnshuId==0) {
throw new RuntimeException("addStu:姓名、专业、学号不能为空!");
}
String sql = "INSERT INTO students (name,qq,major,entrytime,gra_school,id_jnshu"
+ ",daily_url,desire,bro_jnshu,knowfrom) VALUES (?,?,?,?,?,?,?,?,?,?)";
int line = jdbcTemplate.update(sql,new Object[] {
name,stu.getQq(),major,stu.getEntryTime(),
stu.getSchool(),jnshuId,stu.getDailyUrl(),stu.getDesire(),
stu.getJnshuBro(),stu.getKnowFrom()});
return line>0?true:false;
}
/* (非 Javadoc)
* @see cn.cage.student.StudentDAO#delStuById(long)
*/
public boolean delStuById(long id) {
// TODO 自动生成的方法存根
String sql = "DELETE FROM students WHERE id=?";
int line = jdbcTemplate.update(sql,id);
return line>0?true:false;
}
/* (非 Javadoc)
* @see cn.cage.student.StudentDAO#delStuByName(java.lang.String)
*/
/*
public int delStuByName(String name) {
// TODO 自动生成的方法存根
String sql = "DELETE FROM students WHERE name=?";
return jdbcTemplate.update(sql,name);
}
*/
/* (非 Javadoc)
* @see cn.cage.student.StudentDAO#delStuByJnshu(java.lang.String, int)
*/
/*
public boolean delStuByJnshu(String major, int jnshuId) {
// TODO 自动生成的方法存根
String sql = "DELETE FROM students WHERE id_jnshu=? and major=?";
int line = jdbcTemplate.update(sql,new Object[] {jnshuId,major});
return line>0?true:false;
}
*/
/* (非 Javadoc)
* 用于日后需要添加通过其他元素删除学生记录时的情况
* @see cn.cage.student.StudentDAO#delStu(cn.cage.student.Student)
*/
public boolean delStu(Student stu) {
// TODO 自动生成的方法存根
return false;
}
/* (非 Javadoc)
* @see cn.cage.student.StudentDAO#updateStu(cn.cage.student.Student)
*/
public boolean updateStu(Student stu, long id) {
// TODO 自动生成的方法存根
String name = stu.getName(), major = stu.getMajor();
int jnshuId = stu.getJnshuId();
if (name==null || major==null || jnshuId==0) {
throw new RuntimeException("updateStu:姓名、专业、学号不能为空!");
}
String sql = "UPDATE students SET name=?,qq=?,major=?,entrytime=?,gra_school=?,id_jnshu=?"
+ ",daily_url=?,desire=?,bro_jnshu=?,knowfrom=? WHERE id=?";
int line = jdbcTemplate.update(sql,new Object[]{
name,stu.getQq(),major,stu.getEntryTime(),
stu.getSchool(),jnshuId,stu.getDailyUrl(),stu.getDesire(),
stu.getJnshuBro(),stu.getKnowFrom(),id});
return line>0?true:false;
}
/* (非 Javadoc)
* @see cn.cage.student.StudentDAO#queryStuById(int)
*/
public Student queryStuById(long id) {
// TODO 自动生成的方法存根
String sql = "SELECT id,create_at,update_at,name,qq,major,entrytime,gra_school" +
",id_jnshu,daily_url,desire,bro_jnshu,knowfrom FROM students WHERE id=?";
Student stu = null;
try {
stu = jdbcTemplate.queryForObject(sql, new QueryStuRowMapper(),id);
} catch (EmptyResultDataAccessException e) {
// TODO 此处可做更复杂的提示动作,比如抛出异常、记录到本地文件、显示到GUI等。
System.out.println("queryStuById:该学生不存在!");
}
return stu;
}
/* (非 Javadoc)
* @see cn.cage.student.StudentDAO#queryStuByName(java.lang.String)
*/
public List<Student> queryStuByName(String name) {
// TODO 自动生成的方法存根
String sql = "SELECT id,create_at,update_at,name,qq,major,entrytime,gra_school" +
",id_jnshu,daily_url,desire,bro_jnshu,knowfrom FROM students WHERE name=?";
List<Student> list = jdbcTemplate.query(sql, new QueryStuRowMapper(),name);
if (list.size()==0) {
System.out.println("queryStuByName:该学生不存在!");
}
return list;
}
/* (非 Javadoc)
* @see cn.cage.student.StudentDAO#queryStuByJnshu(java.lang.String, int)
*/
public Student queryStuByJnshu(String major, int jnshuId) {
// TODO 自动生成的方法存根
String sql = "SELECT id,create_at,update_at,name,qq,major,entrytime,gra_school,id_jnshu" +
",daily_url,desire,bro_jnshu,knowfrom FROM students WHERE id_jnshu=? and major=?";
Student stu = null;
try {
stu = jdbcTemplate.queryForObject(sql, new QueryStuRowMapper(),new Object[]{jnshuId,major});
} catch (EmptyResultDataAccessException e) {
// TODO 此处可做更复杂的提示动作,比如抛出异常、记录到本地文件、显示到GUI等。
System.out.println("queryStuByJnshu:该学生不存在!");
}
return stu;
}
/* (非 Javadoc)
* 用于日后需要添加通过其他元素查询学生记录时的情况
* @see cn.cage.student.StudentDAO#queryStu(cn.cage.student.Student)
*/
public Student queryStu(Student stu) {
// TODO 自动生成的方法存根
return null;
}
}
提取出的RowMapper实现类:
注:从Mysql中获取的Date值,在java中是java.sql.Date,toString的格式为YYYY-MM-dd。
修改:
* 1.给entrytime的设定语句加上非空判断,否则当其为空时,null.toString抛出空指针异常。
package cn.cage.student;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
/**
* @ClassName QueryStuRowMapper
* @description 直接使用此类建立的对象时,sql语句应查询Student的所有属性。
* @author Cage Yang
*/
public class QueryStuRowMapper implements RowMapper<Student> {
/**
* 直接使用此类建立的对象时,sql语句应查询Student的所有属性。
* @see org.springframework.jdbc.core.RowMapper#mapRow(java.sql.ResultSet, int)
*/
public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
// TODO 自动生成的方法存根
Student stu = new Student(rs.getString("name"), rs.getString("major"), rs.getInt("id_jnshu"));
stu.setId(rs.getLong("id"));
stu.setCreateTime(rs.getLong("create_at"));
stu.setUpdateTime(rs.getLong("update_at"));
stu.setQq(rs.getString("qq"));
// TODO 从Mysql中获取的Date值,在java中是java.sql.Date,toString的格式为YYYY-MM-dd。
Date entryTime = rs.getDate("entrytime");
if (entryTime!=null) {
stu.setEntryTime(entryTime.toString());
}
stu.setSchool(rs.getString("gra_school"));
stu.setDailyUrl(rs.getString("daily_url"));
stu.setDesire(rs.getString("desire"));
stu.setJnshuBro(rs.getString("bro_jnshu"));
stu.setKnowFrom(rs.getString("knowfrom"));
return stu;
}
}
public class DAOFactory {
public static StudentDAO getDAOImpl() {
return new StudentDAOSpringImpl();
}
}
7.测试类
错误原因:a.数据库名是students,少了个s;b.是正斜杠而不是反斜杠
bug2:Access denied for user 'asus'@'localhost' (using password: YES)
错误定位:db.properties读取(<context:property-placeholder location="classpath:db.properties"/>)发生错误。
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:db.properties"></property>
</bean>
即可正常读取。bug3:Table 'students.student' doesn't exist
错误原因:各sql语句中插入的表名是student,应该为students
bug4:Column 'jnshuId' not found.
错误原因:mapRow中的rs.getString("")引号中应为数据库的列名,而不是Student类中的属性名 。
bug5:打印结果为数组地址
修改:将showStu函数中的sop(obj)改为foreach循环遍历。
Warn:Sat Aug 05 03:09:59 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
原因:未设置数据库的连接属性(是否使用SSL)。
Student stu = test.stuDAO.queryStuById(110);
test.showStu(stu);
结果:
Student stu = test.stuDAO.queryStuByName("胡凯博");
test.showStu(stu);
结果:
原因:返回了大量同名的学生。
- 各查询函数中,添加对要查询的学生不存在的情况的处理
- 通过name查询学生时,返回值改为List<Student>,因为可能有重名学生
- 通过name删除学生时,返回值改为int,因为可能删除多名学生
所以,在通过id、专业+学号查询时,通过try-catch捕获异常,给出查询结果为空的提示;通过name查询时,改为调用query方法。
/**
* @FileName:StuDaoImplTest.java
* @description:
* @author Cage Yang
* @version
* Modified Date:2017年8月8日
* Why & What is modified: <修改原因描述>
*/
package cn.cage.student;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.Iterator;
import java.util.List;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* @ClassName StuDaoImplTest
* @description
* @author Cage Yang
*/
public class StuDaoImplTest {
private static StudentDAOImpl stuDao = null;
/**
* @description
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
stuDao = new StudentDAOImpl();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
stuDao = null;
}
/**
* {@link cn.cage.student.StudentDAOImpl#addStu(cn.cage.student.Student)} 的测试方法。
*/
@Test
public void testAddStu() {
Student stu = new Student("王五", "Java后端工程师", 1501);
assertTrue("插入失败!",stuDao.addStu(stu));
assertEquals("插入错误,或查询byJnshu出错", stu, stuDao.queryStuByJnshu("Java后端工程师", 1500));
}
/**
* {@link cn.cage.student.StudentDAOImpl#delStuById(long)} 的测试方法。
*/
@Test
public void testDelStuById() {
assertTrue("删除失败!",stuDao.delStuById(3));
assertNull("删除错误,或查询byId出错", stuDao.queryStuById(3));
}
/**
* {@link cn.cage.student.StudentDAOImpl#updateStu(cn.cage.student.Student, long)} 的测试方法。
*/
@Test
public void testUpdateStu() {
Student stu = new Student("王五", "Java后端工程师", 1502);
stu.setDesire("哈哈哈哈哈哈哈哈");
assertTrue("更新失败!", stuDao.updateStu(stu, 2));
assertEquals("更新错误,或查询byId出错", "哈哈哈哈哈哈哈哈", stuDao.queryStuById(2).getDesire());
}
/**
* {@link cn.cage.student.StudentDAOImpl#queryStuByName(java.lang.String)} 的测试方法。
*/
@Test
public void testQueryStuByName() {
List<Student> list = stuDao.queryStuByName("王五");
for (Iterator<Student> iterator = list.iterator(); iterator.hasNext();) {
Student student = (Student) iterator.next();
if (student.getJnshuId()==1509) {
System.out.println(student.getEntryTime());
assertEquals("查询byName出错", "2017-08-06", student.getEntryTime());
}
}
}
}
- 即使不存在安全性问题,MySQL也应该设定密码。否则可能出现程序无法连接到数据库的情况。
- POJO类中,尽量做到各属性名称、数据类型都和数据库中相同,这样可以免去很多麻烦。
- POJO类都要自定义toString、hashCode、equals、compareTo方法。特别是前三者,比较两个实例是否相同是一个很常见的操作,如果不自定义,根本无法比较。compareTo是考虑到实例可能存入TreeSet,最好自定义;不过即使不自定义,也可通过比较器来实现比较功能。
- 对于DAO接口及其实现类,增删改最好返回int型(影响行数);在insert、update数据时,要考虑到数据库设计时加了非空约束的列,对应属性为空值时直接抛出异常,不向数据库提交数据;delete方法一般只需要一个(比如id)即可,因为正常逻辑是先查询到要删除的数据,在根据查询结果中对应的id删除即可;在select数据时,要考虑到查询值不存在、查询值不唯一的情况,做出应对,避免抛出意料外的异常。
- 学习了JUnit4单元测试的编写与使用。