# 数据源与注解
这里主要讲Spring数据源的集成以及注解的使用
# 连接数据源
我们使用数据连接池来连接数据源,数据库连接池的作用为:
- 数据源(连接池)是提高程序性能如出现的
- 事先实例化数据源,初始化部分连接资源
- 使用连接资源时从数据源中获取
- 使用完毕后将连接资源归还给数据源
常见的连接池有DBCP、C3P0、BoneCP、Druid。
那么连接步骤为:
- 导入数据源的坐标和数据库驱动坐标
- 创建数据源对象
- 设置数据源的基本连接数据
- 使用数据源获取连接资源和归还连接资源
现在先导入依赖坐标,pom.xml文件内容:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
</dependencies>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# java直接连接
使用java代码直接连接:
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.mchange.v2.c3p0.ComboPooledDataSource;
@Test
public void test1() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("org.mariadb.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mariadb://10.0.10.150:6612/test");
dataSource.setUser("root");
dataSource.setPassword("666666");
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
@Test
public void test2() throws Exception {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("org.mariadb.jdbc.Driver");
dataSource.setUrl("jdbc:mariadb://10.0.10.150:6612/test");
dataSource.setUsername("root");
dataSource.setPassword("666666");
DruidPooledConnection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 配置文件连接
下面是配置文件jdbc.properties的内容:
jdbc.driver=org.mariadb.jdbc.Driver
jdbc.url=jdbc:mariadb://10.0.10.150:6612/test
jdbc.username=root
jdbc.password=666666
2
3
4
使用该配置文件连接:
import java.util.ResourceBundle;
@Test
//使用配置文件连接数据库
public void test3() throws Exception {
ResourceBundle rb = ResourceBundle.getBundle("jdbc");
String driver = rb.getString("jdbc.driver");
String url = rb.getString("jdbc.url");
String username = rb.getString("jdbc.username");
String password = rb.getString("jdbc.password");
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl(url);
dataSource.setDriverClass(driver);
dataSource.setUser(username);
dataSource.setPassword(password);
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Spring连接数据源
Spring可以把信息写到applicationContext.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="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="org.mariadb.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mariadb://10.0.10.150:6612/test"></property>
<property name="user" value="root"></property>
<property name="password" value="666666"></property>
</bean>
</beans>
2
3
4
5
6
7
8
9
10
11
12
使用该xml连接数据源:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@Test
//测试Spring容器连接数据源
public void test4() throws Exception {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = app.getBean(DataSource.class);
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
2
3
4
5
6
7
8
9
10
11
12
也可以使用applicationContext加载配置文件来连接数据源,其内容修改为:
<?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"
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.xsd">
<!-- 加载配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# JdbcTemplate
它是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和HibernateTemplate,操作nosql数据库的RedisTemplate,操作消息队列的JmsTemplate等等。
使用JdbcTemplate开发步骤如下:
- 导入spring-jdbc和spring-tx坐标
- 创建数据库表和实体
- 创建JdbcTemplate对象
- 执行数据库操作
使用spring jdbctemplate连接数据库,pom.xml中添加:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
2
3
4
5
6
7
8
9
10
测试一下链接:
package com.muyun.test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import java.beans.PropertyVetoException;
public class JdbcTemplateTest {
@Test
public void test1() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("org.mariadb.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mariadb://10.0.10.150:6612/test");
dataSource.setUser("root");
dataSource.setPassword("666666");
//设置数据源对象
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
int row = jdbcTemplate.update("insert into account values(?,?)","li",5000);
System.out.println(row);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
我们可以将JdbcTemplate的创建权交给Spring,将数据源DataSource的创建权也交给Spring,在Spring容器内部将数据源DataSource注入到JdbcTemplate模版对象中,配置如下:
<?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"
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.xsd">
<!--加载配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置组件扫描-->
<context:component-scan base-package="com.muyun"/>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
再进行测试:
@Test
public void test2() {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbcTemplate = app.getBean(JdbcTemplate.class);
int row = jdbcTemplate.update("insert into account values(?,?)","zhang",3000);
System.out.println(row);
}
2
3
4
5
6
7
下面使用jdbcTemplate进行简单查询:
package com.muyun.test;
import com.muyun.domain.Account;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdbcTemplateCRUDTest {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void testUpdate(){
jdbcTemplate.update("update account set money=? where name=?",999,"li");
}
@Test
public void testDelete(){
jdbcTemplate.update("delete from account where name=?","li");
}
@Test
public void testQueryAll(){
List<Account> accountList = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper<Account>(Account.class));
System.out.println(accountList);
}
@Test
public void testQueryOne(){
Account account = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper<Account>(Account.class),"li");
System.out.println(account);
}
@Test
public void testQueryCount(){
Long aLong = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
System.out.println(aLong);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 注解开发
Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。注解分为原始注解和新注解。
# 原始注解
Spring的原始主要替代<Bean>的配置:
注解名 | 说明 |
---|---|
@Component | 使用在类上用于实例化Bean |
@Controller | 使用在web层类上用于实例化Bean |
@Service | 使用在service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用用于根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是Bean的销毁方法 |
# 使用注解
我们之前在applicationContext.xml中进行注入,也可以使用注解进行注入:
原来的配置为:
<bean id="userDao" class="com.muyun.dao.impl.UserDaoImpl"></bean>
<bean id="userService" class="com.muyun.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
2
3
4
5
使用注解替代UserDaoImpl.java中内容为:
@Component("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save method!");
}
}
2
3
4
5
6
7
8
UserServiceImpl.java中内容为:
@Component("userService")
public class UserServiceImpl implements UserService {
@Autowired //按照数据类型从Spring容器中进行匹配的,如果有多个需要按照名称来匹配,就是下面
@Qualifier("userDao") //按照名称id从容器中进行匹配的,但是主要此处@Qualifier要结合@Autowired一起使用
//@Resource(name="userDao") //@Resource相当于@Qualifier+@Autowired
private UserDao userDao;
/*使用注解set方法可以注释掉
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}*/
@Override
public void save() {
userDao.save();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
上面配置完后,还需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法。在该文件中添加:
<context:component-scan base-package="com.muyun"/>
由于Component并不能很好表明该类是属于哪一层,Spring又提供了Controller,Service,Repository来使用,它们和Component一样,只不过更语义化。
也可以通过注解来引用applicationContext.xml中的信息:
@Value("${jdbc.username}")
private String testName;
2
通过注解控制类的Scope:
@Service("userService")
@Scope("singleton")
public class UserServiceImpl implements UserService {
}
2
3
4
通过注解来说明初始化方法:
@PostConstruct
public void init(){
System.out.println("Service对象初始化方法!");
}
2
3
4
通过注解来说明销毁方法:
@PreDestroy
public void destroy(){
System.out.println("Service对象的销毁方法!");
}
2
3
4
手动关闭容器来触发销毁方法:
public class UserController {
public static void main(String[] args) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = app.getBean(UserService.class);
userService.save();
app.close();
}
}
2
3
4
5
6
7
8
# 新注解
使用原始注解不能替代全部xml配置文件,比如:
- 非自定义的Bean的配置:<bean>
- 加载properties文件的配置:<context:property-placeholder>
- 组件扫描的配置:<context:component-scan>
- 引入其他文件:<import>
这个时候就可以使用Spring新注解:
注解名字 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解 |
@ComponentScan | 用于指定 Spring 在初始化容器时要扫描的包。作用和在 Spring 的 xml 配置文件中的<context:component-scan base-package="com.muyun"/>一样 |
@Bean | 使用在方法上,标注将该方法的返回值存储到 Spring 容器中 |
@PropertySource | 用于加载.properties 文件中的配置 |
@Import | 用于导入其他配置类 |
# 使用新注解
创建SpringConfiguration.java文件:
package com.muyun.config;
import org.springframework.context.annotation.*;
//标志该类是Spring的核心配置类,相当于<context:component-scan base-package="com.muyun"/>
@Configuration
@ComponentScan("com.muyun")
@Import({DataSourceConfiguration.class})
public class SpringConfiguration {
}
2
3
4
5
6
7
8
9
10
11
创建DataSourceConfiguration.java文件:
package com.muyun.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import java.beans.PropertyVetoException;
//下面加载配置文件,相当于<context:property-placeholder location="classpath:jdbc.properties"/>
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource") //Spring会将当前方法的返回值以指定名称存储到Spring容器中
public ComboPooledDataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
System.out.println(driver);
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
使用该配置:
@Test
public void test5() throws PropertyVetoException, SQLException {
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);
DataSource dataSource = app.getBean(DataSource.class);
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
2
3
4
5
6
7
8
# Spring集成Junit
原始Junit测试Spring时会发现在每个测试中都有:
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = app.getBean(DataSource.class);
2
上面是要获取容器,又不能不写,这会造成冗余,为了解决这个问题:
- 让SpringJunit负责创建Spring容器,但是需要将配置文件的名称告诉它
- 将需要进行测试Bean直接在测试类中进行注入
Spring集成Junit步骤:
- 导入spring集成Junit的坐标
- 使用@Runwith注解替换原来的运行期
- 使用@ContextConfiguration指定配置文件或配置类
- 使用@Autowired注入需要测试的对象
- 创建测试方法进行测试
pom.xml中添加依赖:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
2
3
4
5
6
7
8
9
10
11
创建SpringJunitTest.java文件:
package com.muyun.test;
import com.muyun.config.SpringConfiguration;
import com.muyun.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.sql.DataSource;
import java.sql.SQLException;
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration("classpath:applicationContext.xml")
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
@Autowired
private UserService userService;
@Autowired
private DataSource dataSource;
@Test
public void test1() throws SQLException {
userService.save();
System.out.println(dataSource.getConnection());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29