SSM系列第2篇IOC容器

基本概念

JavaBeans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)中。特点是可序列化,提供无参构造器(英语:Nullary constructor),提供getter方法和setter方法访问对象的属性。名称中的“Bean”是用于Java的可重用软件组件的惯用叫法。bean类必须满足以下规范:

  • 有一个public的无参构造
  • 属性可以通过get、set方法访问
  • 可以被序列化

IOC是Inversion of Control的缩写,译为控制反转。其核心理念是通过Spring提供的Ioc容器来管理bean组件。包括组件的生命周期管理、配置和组装服务、AOP支持,以及建立在AOP基础上的声明式事务服务等。

在IoC模式下,控制权发生了反转,即从应用程序转移到了IoC容器,所有组件不再由应用程序自己创建和配置,而是由IoC容器负责,这样,应用程序只需要直接使用已经创建好并且配置好的组件。为了能让组件在IoC容器中被“装配”出来,这种技术叫做依赖注入。依赖注入(dependency injection,缩写为 DI)是一种软件设计模式,也是实现控制反转的其中一种技术。这种模式能让一个物件接收它所依赖的其他物件。“依赖”是指接收方所需的对象。“注入”是指将“依赖”传递给接收方的过程。DI容器底层最基本的设计思路就是基于工厂模式的。DI容器的核心功能一般有三个:配置解析、对象创建和对象生命周期管理。在Spring框架中是使用xml或者注解的方式来配置需要注入的组件

装配Bean

Spring框架提供了xml文件和注解两种方式来装配Bean。需要创建一个maven项目,然后导入spring的依赖,导入依赖之后就可以new一个spring的配置文件m,或者使用注解的方式装配。通过scope指定是用的单例模式(singleton)还是原型模式(prototype),默认用的是单例模式

依赖参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.eldpepar</groupId>
<artifactId>SpringDemo</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
</project>

StudentMain.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import bean.Student;
import config.StudentConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StudentMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
student.name = "张三";
student.age = 24;
System.out.println(student);

//注解方式
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(StudentConfiguration.class);
Student stu = (Student) applicationContext.getBean(Student.class);
stu.name = "李四";
stu.age = 23;
System.out.println(stu);
}
}

xml方式

通过xml方式需要指定类的名字(不区分大小写)。类的详细路径,如果在根路径则不需要指定路径
applicationContext.xml

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="student" class="bean.Student"/>

</beans>

Student.java

1
2
3
4
5
6
7
8
9
10
11
12
import bean.Student;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Student {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("STUDENT");
student.name = "张三";
student.age = 24;
System.out.println(student);
}
}

注解方式

方式一

单个文件配置
StudentConfiguration.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package config;

import bean.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class StudentConfiguration {

@Bean
Student getStudent() {
return new Student();
}
}
方式二

扫描bean包
Car.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package bean;

import org.springframework.stereotype.Component;

@Component
public class Car {
public int id;
public String brand;

@Override
public String toString() {
return "Car{" +
"id=" + id +
", brand='" + brand + '\'' +
'}';
}
}

CarConfigScan.java

1
2
3
4
5
6
7
8
9
10
package config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("bean")
public class CarConfigScan {

}

CarMain.java

1
2
3
4
5
6
7
8
9
10
11
12
13
import bean.Car;
import config.CarConfigScan;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class CarMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(CarConfigScan.class);
Car car = applicationContext.getBean(Car.class);
car.id = 101;
car.brand = "奔驰";
System.out.println(car);
}
}

依赖注入

可以使用property标签来实现对Bean的成员属性进行赋值呢,如果注入的是基本数据类型则通过value来注入(例如数据库相关的配置)集合类通过list,map等方式进行注入。通过注解则使用的是@Resource和@Autowired

  • 每个<bean …>都有一个id标识,相当于Bean的唯一ID;
  • 通过注入了另一个Bean;
  • Bean的顺序不重要,Spring根据依赖关系会自动正确初始化

xml方式

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean name="money" class="bean.Money">
<property name="value" value="213.23"/>
</bean>
<bean name="people" class="bean.People">
<property name="name" value="小明"/>
<property name="money" ref="money"/>
</bean>
</beans>

People.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package bean;

public class People {
private String name;
private Money money;

@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", money=" + money +
'}';
}

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

public void setMoney(Money money) {
this.money = money;
}
}

Money.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package bean;

public class Money {
private double value;

public void setValue(double value) {
this.value = value;
}

@Override
public String toString() {
return "Money{" +
"value=" + value +
'}';
}
}

Money.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package bean;

public class Money {
private double value;

public void setValue(double value) {
this.value = value;
}

@Override
public String toString() {
return "Money{" +
"value=" + value +
'}';
}
}

PeopleMain.java

1
2
3
4
5
6
7
8
9
10
import bean.People;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class PeopleMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = (People) context.getBean("people");
System.out.println(people);
}
}

注解方式

注解使用@Resource和@Autowired来实现依赖注入,@Resource默认ByName如果找不到则ByType,可以添加到set方法、字段上。@Autowired默认是byType,可以添加在构造方法、set方法、字段、方法参数上。可以给@Autowired增加一个required = false的参数,适合有定义就使用定义,没有就使用默认值的情况

UserConfig.java

1
2
3
4
5
6
7
8
9
package config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("user")
public class UserConfig {
}

UserService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package user.service;

import org.springframework.stereotype.Component;
import user.mapper.UserMapper;

import javax.annotation.Resource;

@Component
public class UserService {
@Resource
private UserMapper userMapper;

public void login() {
System.out.println("UserService-----login");
userMapper.login();
}
}

UserMapper.java

1
2
3
4
5
6
7
8
9
10
package user.mapper;

import org.springframework.stereotype.Component;

@Component
public class UserMapper {
public void login() {
System.out.println("--------UserMapper");
}
}

UserMain.java

1
2
3
4
5
6
7
8
9
10
11
12
import config.UserConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import user.service.UserService;

public class UserMain {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(UserConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.login();
}
}

定制Bean

Spring默认使用Singleton创建Bean,也可指定Scope为Prototype;可将相同类型的Bean注入List;可用@Autowired(required=false)允许可选注入;
可用带@Bean标注的方法创建Bean;可使用@PostConstruct和@PreDestroy对Bean进行初始化和清理;相同类型的Bean只能有一个指定为@Primary,其他必须用@Quanlifier(“beanName”)指定别名;注入时,可通过别名@Quanlifier(“beanName”)指定某个Bean;可以定义FactoryBean来使用工厂模式创Bean。

代码示例

MailConfig.java

1
2
3
4
5
6
7
8
9
package mail;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("mail")
public class MailConfig {
}

MailService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package mail;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.time.ZoneId;

@Component
public class MailService {
@Autowired(required = false)
ZoneId zoneId = ZoneId.systemDefault();

@PostConstruct
public void init() {
System.out.println("Init mail service with zoneId = " + this.zoneId);
}

@PreDestroy
public void shutdown() {
System.out.println("Shutdown mail service");
}
}

MailMain.java

1
2
3
4
5
6
7
8
9
10
11
12
13
package mail;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MailMain {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MailConfig.class);
MailService mailService = applicationContext.getBean(MailService.class);
mailService.shutdown();
}
}

条件装配

Spring允许通过@Profile配置不同的Bean。需要运行java时指定环境-Dspring.profiles.active=test,master,可以同时指定多个Profile。同时提供了@Conditional来进行条件装配,Spring Boot在此基础上进一步提供了基于配置、Class、Bean等条件进行装配。指定的Conditional如果是类的话,需要该类实现Condition接口来指定条件。如果是配置文件用的是@ConditionalOnProperty注解

综合案例

本案例使用了廖雪峰老师的数据库操作的案例。廖雪峰老师推荐使用HSQLDB这个数据库,优点是无需本地安装数据库,非常使用用于简单项目的测试

JdbcTemplate的用法

  • 针对简单查询,优选query()和queryForObject(),因为只需提供SQL语句、参数和RowMapper;
  • 针对更新操作,优选update(),因为只需提供SQL语句和参数;
  • 任何复杂的操作,最终也可以通过execute(ConnectionCallback)实现,因为拿到Connection就可以做任何JDBC操作

相关依赖

1
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.eldpepar</groupId>
<artifactId>SpringDemo</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>

<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.2</version>
</dependency>

<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.5.0</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>

<!--日志,不添加会提示-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>

</dependencies>
</project>

实现代码

jdbc.properties

1
2
3
4
5
6
# 数据库文件名为testdb:
jdbc.url=jdbc:hsqldb:file:user

# Hsqldb默认的用户名是sa,口令是空字符串:
jdbc.username=sa
jdbc.password

AppConfig.java

1
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
package jdbc;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
@ComponentScan
@PropertySource("jdbc.properties")
public class AppConfig {

@Value("${jdbc.url}")
String jdbcUrl;

@Value("${jdbc.username}")
String jdbcUsername;

@Value("${jdbc.password}")
String jdbcPassword;

@Bean
DataSource createDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(jdbcUrl);
config.setUsername(jdbcUsername);
config.setPassword(jdbcPassword);
config.addDataSourceProperty("autoCommit", "true");
config.addDataSourceProperty("connectionTimeout", "5");
config.addDataSourceProperty("idleTimeout", "60");
return new HikariDataSource(config);
}

@Bean
JdbcTemplate createJdbcTemplate(@Autowired DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}

DatabaseInitializer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package jdbc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

@Component
public class DatabaseInitializer {
@Autowired
JdbcTemplate jdbcTemplate;

@PostConstruct
public void init() {
jdbcTemplate.update("CREATE TABLE IF NOT EXISTS users (" //
+ "id BIGINT IDENTITY NOT NULL PRIMARY KEY, " //
+ "email VARCHAR(100) NOT NULL, " //
+ "password VARCHAR(100) NOT NULL, " //
+ "name VARCHAR(100) NOT NULL, " //
+ "UNIQUE (email))");
}
}

DataRandom.java

1
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package jdbc;
/**
* 随机生成中文姓名,邮箱
* 代码源于网络 由kingYiFan整理 create2019/05/24
*/
public class DataRandom {

//百家姓
private static String surname = "赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹喻柏水窦章云苏潘葛奚范彭郎鲁韦昌马苗凤花方俞任袁柳酆鲍史唐费廉岑薛雷贺倪汤滕殷罗毕郝邬安常乐于时傅皮卞齐康伍余元卜顾孟平黄和穆萧尹姚邵湛汪祁毛禹狄米贝明臧计伏成戴谈宋茅庞熊纪舒屈项祝董梁杜阮蓝闵席季麻强贾路娄危江童颜郭梅盛林刁钟徐邱骆高夏蔡田樊胡凌霍虞万支柯咎管卢莫经房裘缪干解应宗宣丁贲邓郁单杭洪包诸左石崔吉钮龚程嵇邢滑裴陆荣翁荀羊於惠甄魏加封芮羿储靳汲邴糜松井段富巫乌焦巴弓牧隗山谷车侯宓蓬全郗班仰秋仲伊宫宁仇栾暴甘钭厉戎祖武符刘姜詹束龙叶幸司韶郜黎蓟薄印宿白怀蒲台从鄂索咸籍赖卓蔺屠蒙池乔阴郁胥能苍双闻莘党翟谭贡劳逄姬申扶堵冉宰郦雍却璩桑桂濮牛寿通边扈燕冀郏浦尚农温别庄晏柴瞿阎充慕连茹习宦艾鱼容向古易慎戈廖庚终暨居衡步都耿满弘匡国文寇广禄阙东殴殳沃利蔚越夔隆师巩厍聂晁勾敖融冷訾辛阚那简饶空曾毋沙乜养鞠须丰巢关蒯相查后江红游竺权逯盖益桓公万俟司马上官欧阳夏侯诸葛闻人东方赫连皇甫尉迟公羊澹台公冶宗政濮阳淳于仲孙太叔申屠公孙乐正轩辕令狐钟离闾丘长孙慕容鲜于宇文司徒司空亓官司寇仉督子车颛孙端木巫马公西漆雕乐正壤驷公良拓拔夹谷宰父谷粱晋楚阎法汝鄢涂钦段干百里东郭南门呼延归海羊舌微生岳帅缑亢况后有琴梁丘左丘东门西门商牟佘佴伯赏南宫墨哈谯笪年爱阳佟";

//女生名
private static String girlName = "秀娟英华慧巧美娜静淑惠珠翠雅芝玉萍红娥玲芬芳燕彩春菊兰凤洁梅琳素云莲真环雪荣爱妹霞香月莺媛艳瑞凡佳嘉琼勤珍贞莉桂娣叶璧璐娅琦晶妍茜秋珊莎锦黛青倩婷姣婉娴瑾颖露瑶怡婵雁蓓纨仪荷丹蓉眉君琴蕊薇菁梦岚苑婕馨瑗琰韵融园艺咏卿聪澜纯毓悦昭冰爽琬茗羽希宁欣飘育滢馥筠柔竹霭凝晓欢霄枫芸菲寒伊亚宜可姬舒影荔枝思丽";

//男生名
private static String boyName = "伟刚勇毅俊峰强军平保东文辉力明永健世广志义兴良海山仁波宁贵福生龙元全国胜学祥才发武新利清飞彬富顺信子杰涛昌成康星光天达安岩中茂进林有坚和彪博诚先敬震振壮会思群豪心邦承乐绍功松善厚庆磊民友裕河哲江超浩亮政谦亨奇固之轮翰朗伯宏言若鸣朋斌梁栋维启克伦翔旭鹏泽晨辰士以建家致树炎德行时泰盛雄琛钧冠策腾楠榕风航弘";

//邮箱
public static String base = "abcdefghijklmnopqrstuvwxyz0123456789";
public static final String[] email_suffix="@gmail.com,@yahoo.com,@msn.com,@hotmail.com,@aol.com,@ask.com,@live.com,@qq.com,@0355.net,@163.com,@163.net,@263.net,@3721.net,@yeah.net,@googlemail.com,@126.com,@sina.com,@sohu.com,@yahoo.com.cn".split(",");
/**
* 生成中文名称
* @return
*/
public static String getChineseName() {
/**
* 生成姓名的男还是女。
*/
String name_sex = "";

int index = getNum(0, surname.length() - 1);
String first = surname.substring(index, index + 1);
int sex = getNum(0, 1);
String str = boyName;
int length = boyName.length();
if (sex == 0) {
str = girlName;
length = girlName.length();
name_sex = "女";
} else {
name_sex = "男";
}
index = getNum(0, length - 1);
String second = str.substring(index, index + 1);
int hasThird = getNum(0, 1);
String third = "";
if (hasThird == 1) {
index = getNum(0, length - 1);
third = str.substring(index, index + 1);
}
return name_sex + ":" + first + second + third;
}

public static int getNum(int start, int end) {
return (int) (Math.random() * (end - start + 1) + start);
}

public static String getEmail(int lMin,int lMax) {
int length=getNum(lMin,lMax);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = (int)(Math.random()*base.length());
sb.append(base.charAt(number));
}
sb.append(email_suffix[(int)(Math.random()*email_suffix.length)]);
return sb.toString();
}
}

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package jdbc;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {
int id;
String name;
String email;
String password;
}

UserService.java

1
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package jdbc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.List;

@Component
public class UserService {
@Autowired
JdbcTemplate jdbcTemplate;

//获取(根据id)
public User getUserById(long id) {
// 注意传入的是ConnectionCallback:
return jdbcTemplate.execute((Connection conn) -> {
// 可以直接使用conn实例,不要释放它,回调结束后JdbcTemplate自动释放:
// 在内部手动创建的PreparedStatement、ResultSet必须用try(...)释放:
try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?")) {
ps.setObject(1, id);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
User user;
user = new User( // new User object:
rs.getInt("id"), // id
rs.getString("name"),// name
rs.getString("email"), // email
rs.getString("password") // password
);
return user;
}
throw new RuntimeException("user not found by id.");
}
}
});
}

//修改用户
public void updateUser(User user) {
// 传入SQL,SQL参数,返回更新的行数:
if (1 != jdbcTemplate.update("UPDATE users SET name = ? WHERE id = ?", user.getName(),user.getId())) {
throw new RuntimeException("User not found by id");
}
}

//添加用户
public User register(String email, String password, String name) {
// 创建一个KeyHolder:
KeyHolder holder = new GeneratedKeyHolder();
if (1 != jdbcTemplate.update(
// 参数1:PreparedStatementCreator
(conn) -> {
// 创建PreparedStatement时,必须指定RETURN_GENERATED_KEYS:
PreparedStatement ps = conn.prepareStatement("INSERT INTO users(email,password,name) VALUES(?,?,?)",
Statement.RETURN_GENERATED_KEYS);
ps.setObject(1, email);
ps.setObject(2, password);
ps.setObject(3, name);
return ps;
},
// 参数2:KeyHolder
holder)
) {
throw new RuntimeException("Insert failed.");
}
// 从KeyHolder中获取返回的自增值:
return new User(holder.getKey().intValue(), email, password, name);
}


public List<User> getUsers(int pageIndex) {
int limit = 100;
int offset = limit * (pageIndex - 1);
return jdbcTemplate.query("SELECT * FROM users LIMIT ? OFFSET ?", new Object[] { limit, offset },
new BeanPropertyRowMapper<>(User.class));
}
}

JdbcMain.java

1
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
package jdbc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.List;

public class JdbcMain {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = applicationContext.getBean(UserService.class);

//插入亿点点数据
for (int i = 0; i < 10000; i++) {
userService.register(DataRandom.getEmail(5,10), "123456", DataRandom.getChineseName());
}

//根据id获取
User user = userService.getUserById(0);
System.out.println(user);

//修改用户
userService.updateUser(User.builder().id(1).
email("lisi@eldpepar.com").
password("654321").
name("王五").build());

//获取所有
List<User> users = userService.getUsers(3);
users.stream().forEach(System.out::println);
}
}

SSM系列第2篇IOC容器
https://www.eldpepar.com/coding/32649/
作者
EldPepar
发布于
2022年11月10日
许可协议