话不多说,我们讨论一下下面几个话题!
1、单元测试在开发中提供哪些便利?
我们上节课,如果想要测试业务逻辑类,需要把web环境跑起来才能进行测试,或者新创建个测试类进行测试,但是真实的开发过程中,我们有千千万万个方法,每个方法都会有自己的逻辑需要测试,这时候我们再创建测试类就已经非常费劲了。然后就有了一个牛人封装了junit4第三方包,让每个方法都可以和主方法一样,单独运行进行测试,我们就称之为单元测试。首先我们需要导入junit的包,pom新增配置如下:
pom.xml
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
使用上节课我们讲到的业务逻辑类举例子,新创建一个普通方法test并进行单元测试:
LoginService.java
package com.login.serviceImpl;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.login.dao.UserMapper;
import com.login.entity.User;
@Service
public class LoginService {
// 把userMapper的映射器注入进来
@Autowired
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
public boolean login(User user) {
User modelUser = userMapper.login(user);
if(user.getPassword().equals(modelUser.getPassword())) {
return true;
}else {
return false;
}
}
@Test
public void test() {
System.out.println("aaaaaa");
}
}
然后鼠标放在方法内,右键选择run as,再选择JUNIT TEST,就可以进行单元测试了。
2、在开发中如何使用日志?
我们工作过程中,经常会遇到各种各样的项目,大的项目或者小的项目都会接触到。小的项目不用多说,我们开发的自由度就会大一些,但是对于一些大的项目,我们就会碰到不知道逻辑错误在哪里的问题,我们如果简单的使用system.out.print来进行打印,就非常有局限性,我们不可以选择性的显示一些打印信息,而且,我们不能讲打印的内容放到文本或者服务器上,这样我们也不好去分析我们的问题所在。
而java的日志很好的解决了这些问题,在java中,最常用的一个日志框架就是log4j,这个日志框架是java编写的一个可靠地日志框架,现在log4j不仅仅在java中使用,还已经被移植到c、c++、python等语言上。
log4j是一个可以高度配置的日志框架,我们可以先来了解一下它的配置文件。
#指定日志级别和命名器的名字
log4j.rootLogger = DEBUG, X
这个配置是给日志指定一个级别debug,然后再给一个命名器X。在这我们主要说一下日志的级别都有哪些。
ALL:所有级别,包括自定义的级别
DEBUG:应用程序调试的级别
ERROR:错误的级别,但是程序仍然可以执行
FATAL:严重错误的级别,程序可能会因此终止
INFO:应用程序信息的级别
OFF:最高的级别,一般为了关闭日志系统
WARN:警告级别,一般是潜在的危险
这些级别都有自己的意义,他们的级别高低程度是:ALL < DEBUG < INFO < WARN < ERROR < FATAL,如果能理解这些级别的意义,那很容易的就可以对级别进行排序,如果实在不理解,可以暂时记忆成“爱的一吻二分哦”,这样,时间长了,理解了,也就记住了我们日志级别的顺序。
比如我的日志级别设置成了WARN,那么我的WARN和ERROR以及FATAL级别的日志都会跟着打印出来。
#给X一个有效的appender
log4j.appender.X=org.apache.log4j.FileAppender
appender是log4j提供的api,我们来看一下都有哪些常用的appender,并且他们都代表什么意义。
org.apache.log4j.ConsoleAppender:将日志输出到控制台
org.apache.log4j.FileAppender:将日志输出到文本文件中
org.apache.log4j.jdbc.JDBCAppender:将日志输出到数据库中
除了这几个常用的appender,还有很多,我们后面会一一补充。
#给到X一个layout,为了指定输出内容的格式
log4j.appender.X.layout=org.apache.log4j.PatternLayout
log4j.appender.X.layout.conversionPattern=%m%n
经常用的两个layout有:HTMLPatternLayout、PatternLayout两种,前者是输出html格式的日志,后者可以指定格式。我们来着重解释一下后者。
如实例中所示,我们可以使用conversionPattern来制定格式,使用%+字母的形式指定格式,我们来看一下不同的字母代表什么意思吧。
到目前为止,我们已经将log4j的日志配置文件了解的差不多了,接下来我们看一下log4j的日志如何在程序中使用。
import org.apache.log4j.Logger;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
public class log4jExample{
/* Get actual class name to be printed on */
static Logger log = Logger.getLogger(
log4jExample.class.getName());
public static void main(String[] args)
throws IOException,SQLException{
log.debug("Hello this is an debug message");
log.info("Hello this is an info message");
}
}
我们这样就可以在不同的地方进行不同级别的日志打印了。
3、开发过程中如何进行事务的管理?
事务是对于数据库操作的一个序列,比如我们最常用的转账,甲给乙转账100元,可以分成两个过程,第一步是甲支出100元,第二步是乙收入100元。我们设想一下,如果甲支出100元,结果系统或者服务器出现故障,那会不会有甲已经支出但是乙没有收到的问题?事务就可以解决这个问题。
事务必须遵循4个原则,我们也称之为ACID,这四个原则分别是:原子性、一致性、隔离性、持久性。
原子性的意思就是一个事务中的若干个操作,要么全被执行,要么全部不被执行。
一致性的意思就是事务的操作必须由一个正确的状态转变为另一个正确的状态。
隔离性的意思就是两个事务之间是不应该相互影响的。
持久性的意思就是事务完成之后,无论程序发生什么错误还是服务器发生什么错误,我们都应该将事务之中的数据存储过程完成。
上面说了事务的四个原则,那么如果不使用事务,我们也会出现下面的几个问题:
- 脏读:A事务增加数据过程中,B进行了读取,A事务回滚,造成B结果的不准确。
- 不可重复读:A在一个事务内,B修改了数据,造成A两次读取数据不同。
- 幻读:A事务读取数据,B事务进行增加数据,造成A对于原来结果的处理。
- 第一类丢失更新:A事务过程中B事务修改了数据,A进行回滚覆盖了B的数据。
- 第二类丢失更新:A事务过程中B事务修改了数据,A事务完成覆盖了B的数据。
java提供了四种隔离机制,如下:
- 读未提交:Read uncommitted,可能造成脏读、幻读、不可重复读
- 读已提交:Read committed,可能造成幻读、不可重复读
- 可重复读:Repeatable read,可能造成幻读
- 可串行化:Serializable,不会造成上面的五个问题
上面简单的介绍了java的事务机制,对于java而言,最常用的是spring中的事务。
4、mybatis提供了什么样的缓存机制?
mybatis提供了两种缓存机制,一种是一级缓存,还有一种是二级缓存。
一级缓存是sqlSession级别的缓存,当我们使用同一个sqlSession第一次执行某个sql语句的时候,会将结果放到缓存中,等下次再执行这个sql的时候会从缓存中去取。当我们使用这个sqlSession执行insert、update、delete的操作时,会清空缓存,保证缓存里的数据是最新的。
二级缓存是mapper级别的缓存,当我们使用多个sqlSession执行同一个mapper时,第一次会将结果放到缓存中,第二次访问直接从缓存中获取。
二级缓存需要我们手动开启,开启配置如下:
mybatis-config.xml
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
5、spring中三种配置数据源的方式?
第一种是spring默认的数据源配置方式,我们可以通过DriverManagerDataSource类来指定数据源,可以配置属性driverClassName来指定驱动器路径,使用url属性指定数据库,使用username属性指定数据库用户名,使用password指定数据库密码。这种数据源配置方式在每一次连接都会创建一个新的连接,当连接的次数达到一定数量,就会出现问题,我们来看一下这种数据源的配置:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/login"></property>
<property name="username" value="root"></property>
<property name="password" value="admin123"></property>
</bean>
第二种数据源配置方式是DBCP的连接池配置方式,通过BasicDataSource来指定数据源。这个配置方式通过配置属性driverClassName来指定驱动器路径,使用url属性指定数据库,使用username属性指定数据库用户名,使用password指定数据库密码。这种配置方式是apache的,他会有一定数量的连接,他每次有连接的时候都会在连接池中寻找已经存在的连接,如果有则使用这个连接,没有就会创建一定数量的连接,他不会自动回收空闲的连接。
<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/login"></property>
<property name="username" value="root"></property>
<property name="password" value="admin123"></property>
</bean>
第三种数据源配置方式是C3P0的方式,这种配置方式通过CompooledDataSource来指定数据源,这个数据源需要单独导包com.mchange.c3p0的包,他是开源的,在市场上比较受欢迎,他也是线程池的方式,会自动回收掉空闲的连接,他通过driverClass属性来指定驱动器,通过jdbcUrl属性来指定数据库,通过user属性指定数据库用户名称,通过password属性指定用户密码。我们看一下这种配置方式:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/login"></property>
<property name="user" value="root"></property>
<property name="password" value="admin123"></property>
</bean>