Spring官网:https://spring.io/
参考视频:
源码仓库:muyoukule/accidence-spring (github.com)
Spring整合JdbcTemplate JdbcTemplate是Spring提供的一个JDBC模板类,是对JDBC的封装,简化JDBC代码。
环境准备
a. 创建数据表
1 2 3 4 5 6 CREATE TABLE `tbl_user` ( `id` int NOT NULL AUTO_INCREMENT, `real_name` varchar(255) DEFAULT NULL, `age` int DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
b. 引入相关依赖
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 <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > 5.3.27</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.13.2</version > <scope > test</scope > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.24</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.31</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.3.27</version > </dependency > </dependencies >
c. 准备实体类
1 2 3 4 5 6 7 8 @Data @NoArgsConstructor @AllArgsConstructor public class User { private Integer id; private String realName; private Integer age; }
d. 编写Spring.xml配置文件
JdbcTemplate 是 Spring 提供好的类,这类的完整类名是:org.springframework.jdbc.core.JdbcTemplate
我们怎么使用这个类呢?new对象就可以了。怎么new对象?直接将这个类配置到Spring配置文件中,纳入Bean管理即可。
1 <bean id ="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate" > </bean >
JdbcTemplate 中有一个 DataSource
属性,这个属性是数据源,我们都知道连接数据库需要 Connection
对象,而生成 Connection
对象是数据源负责的。所以我们需要给 JdbcTemplate 设置数据源属性。
所有的数据源都是要实现 javax.sql.DataSource
接口的。这个数据源可以自己写一个,也可以用写好的。比如:阿里巴巴的德鲁伊连接池,c3p0,dbcp等。
e. 手写一个数据源
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 @Setter @ToString public class MyDataSource implements DataSource { private String driver; private String url; private String username; private String password; @Override public Connection getConnection () throws SQLException { try { Class.forName(driver); Connection conn = DriverManager.getConnection(url, username, password); return conn; } catch (Exception e) { e.printStackTrace(); } return null ; } }
f. 数据源传递给JdbcTemplate
写完数据源,我们需要把这个数据源传递给 JdbcTemplate 。因为 JdbcTemplate 中有一个 DataSource
属性:
1 2 3 4 5 6 7 8 9 <bean id ="myDataSource" class ="com.muyoukule.Datasource.MyDataSource" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/spring_db" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </bean > <bean id ="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate" > <property name ="dataSource" ref ="myDataSource" /> </bean >
到这里环境就准备好了。
新增
编写测试程序:
1 2 3 4 5 6 7 8 9 10 11 @Test public void testInsert () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("spring.xml" ); JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate" , JdbcTemplate.class); String sql = "insert into tbl_user(id,real_name,age) values(?,?,?)" ; int count = jdbcTemplate.update(sql, null , "张三" , 30 ); System.out.println("插入的记录条数:" + count); }
update
方法有两个参数:
第一个参数:要执行的 SQL 语句。(SQL语句中可能会有占位符 ? )
第二个参数:可变长参数,参数的个数可以是0个,也可以是多个。一般是 SQL 语句中有几个问号,则对应几个参数。
修改
1 2 3 4 5 6 7 8 9 10 @Test public void testUpdate () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("spring.xml" ); JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate" , JdbcTemplate.class); String sql = "update tbl_user set real_name = ?, age = ? where id = ?" ; int count = jdbcTemplate.update(sql, "张三丰" , 55 , 1 ); System.out.println("更新的记录条数:" + count); }
删除
1 2 3 4 5 6 7 8 9 10 @Test public void testDelete () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("spring.xml" ); JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate" , JdbcTemplate.class); String sql = "delete from tbl_user where id = ?" ; int count = jdbcTemplate.update(sql, 1 ); System.out.println("删除了几条记录:" + count); }
查询一个对象
1 2 3 4 5 6 7 8 9 10 @Test public void testSelectOne () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("spring.xml" ); JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate" , JdbcTemplate.class); String sql = "select id, real_name, age from tbl_user where id = ?" ; User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper <>(User.class), 2 ); System.out.println(user); }
因为刚才已经将数据库数据删除了,所以需要先插入再测试查询
1 User(id=2, realName=张三, age=30)
queryForObject方法三个参数:
第一个参数:sql语句
第二个参数:Bean属性值和数据库记录行的映射对象。在构造方法中指定映射的对象类型。
第三个参数:可变长参数,给sql语句的占位符问号传值。
查询多个对象
1 2 3 4 5 6 7 8 9 10 @Test public void testSelectAll () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("spring.xml" ); JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate" , JdbcTemplate.class); String sql = "select id, real_name, age from tbl_user" ; List<User> users = jdbcTemplate.query(sql, new BeanPropertyRowMapper <>(User.class)); System.out.println(users); }
查询前先使用不同的数据多次执行插入方法
1 [User(id=2, realName=张三, age=30), User(id=3, realName=李四, age=31), User(id=4, realName=王五, age=32)]
查询一个值
1 2 3 4 5 6 7 8 9 10 @Test public void testSelectOneValue () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("spring.xml" ); JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate" , JdbcTemplate.class); String sql = "select count(1) from tbl_user" ; Integer count = jdbcTemplate.queryForObject(sql, int .class); System.out.println("总记录条数:" + count); }
批量添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Test public void testAddBatch () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("spring.xml" ); JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate" , JdbcTemplate.class); String sql = "insert into tbl_user(id,real_name,age) values(?,?,?)" ; Object[] objs1 = {null , "小花" , 20 }; Object[] objs2 = {null , "小明" , 21 }; Object[] objs3 = {null , "小刚" , 22 }; List<Object[]> list = new ArrayList <>(); list.add(objs1); list.add(objs2); list.add(objs3); int [] count = jdbcTemplate.batchUpdate(sql, list); System.out.println(Arrays.toString(count)); }
批量修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test public void testUpdateBatch () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("spring.xml" ); JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate" , JdbcTemplate.class); String sql = "update tbl_user set real_name = ?, age = ? where id = ?" ; Object[] objs1 = {"小花11" , 10 , 5 }; Object[] objs2 = {"小明22" , 12 , 6 }; Object[] objs3 = {"小刚33" , 9 , 7 }; List<Object[]> list = new ArrayList <>(); list.add(objs1); list.add(objs2); list.add(objs3); int [] count = jdbcTemplate.batchUpdate(sql, list); System.out.println(Arrays.toString(count)); }
批量删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Test public void testDeleteBatch () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("spring.xml" ); JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate" , JdbcTemplate.class); String sql = "delete from tbl_user where id = ?" ; Object[] objs1 = {5 }; Object[] objs2 = {6 }; Object[] objs3 = {7 }; List<Object[]> list = new ArrayList <>(); list.add(objs1); list.add(objs2); list.add(objs3); int [] count = jdbcTemplate.batchUpdate(sql, list); System.out.println(Arrays.toString(count)); }
使用回调函数
使用回调函数,可以参与的更加细节:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Test public void testCallback () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("spring.xml" ); JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate" , JdbcTemplate.class); String sql = "select id, real_name, age from tbl_user where id = ?" ; User user = jdbcTemplate.execute(sql, new PreparedStatementCallback <User>() { @Override public User doInPreparedStatement (PreparedStatement ps) throws SQLException, DataAccessException { User user = null ; ps.setInt(1 , 2 ); ResultSet rs = ps.executeQuery(); if (rs.next()) { user = new User (); user.setId(rs.getInt("id" )); user.setRealName(rs.getString("real_name" )); user.setAge(rs.getInt("age" )); } return user; } }); System.out.println(user); }
1 User(id=2, realName=张三, age=30)
使用德鲁伊连接池
之前数据源是用我们自己写的。也可以使用别人写好的。例如德鲁伊连接池。
a. 引入德鲁伊连接池的依赖。
1 2 3 4 5 <dependency > <groupId > com.alibaba</groupId > <artifactId > druid</artifactId > <version > 1.1.16</version > </dependency >
b. 将德鲁伊中的数据源配置到 spring 配置文件中。和配置我们自己写的一样。
1 2 3 4 5 6 7 8 9 10 <bean id ="druidDataSource" class ="com.alibaba.druid.pool.DruidDataSource" > <property name ="driverClassName" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/spring_db" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </bean > <bean id ="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate" > <property name ="dataSource" ref ="druidDataSource" /> </bean >
1 User(id=2, realName=张三, age=30)
Spring整合Mybatis 1. Spring整合Mybatis思路分析
环境准备
在准备环境的过程中,先回顾下Mybatis开发的相关内容:
a. 准备数据库表
Mybatis是来操作数据库表,所以先创建一个数据库及表
1 2 3 4 5 6 7 create database spring_db character set utf8;use spring_db; create table tbl_account( id int primary key auto_increment, name varchar (35 ), money double );
b. 引入相关依赖
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 <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > 5.3.27</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.24</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.31</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.6</version > </dependency > <dependency > <groupId > com.alibaba</groupId > <artifactId > druid</artifactId > <version > 1.1.16</version > </dependency > </dependencies >
c. 根据表创建模型类
1 2 3 4 5 6 7 8 @Data @NoArgsConstructor @AllArgsConstructor public class Account implements Serializable { private Integer id; private String name; private Double money; }
d. 创建 Dao 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public interface AccountDao { @Insert("insert into tbl_account(name,money)values(#{name},#{money})") void save (Account account) ; @Delete("delete from tbl_account where id = #{id} ") void delete (Integer id) ; @Update("update tbl_account set name = #{name} , money = #{money} where id = #{id} ") void update (Account account) ; @Select("select * from tbl_account") List<Account> findAll () ; @Select("select * from tbl_account where id = #{id} ") Account findById (Integer id) ; }
e. 创建 Service 接口和实现类
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 public interface AccountService { void save (Account account) ; void delete (Integer id) ; void update (Account account) ; List<Account> findAll () ; Account findById (Integer id) ; } @Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; public void save (Account account) { accountDao.save(account); } public void update (Account account) { accountDao.update(account); } public void delete (Integer id) { accountDao.delete(id); } public Account findById (Integer id) { return accountDao.findById(id); } public List<Account> findAll () { return accountDao.findAll(); } }
f. 添加 jdbc.properties
文件
resources 目录下添加,用于配置数据库连接四要素
1 2 3 4 jdbc.driver =com.mysql.jdbc.Driver jdbc.url =jdbc:mysql://localhost:3306/spring_db?useSSL=false jdbc.username =root jdbc.password =root
useSSL:关闭 MySQL 的 SSL 连接
g. 添加 Mybatis 核心配置文件(SqlMapConfig.xml)
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 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <properties resource ="jdbc.properties" /> <typeAliases > <package name ="com.muyoukule.Entity" /> </typeAliases > <environments default ="mysql" > <environment id ="mysql" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> </dataSource > </environment > </environments > <mappers > <package name ="com.muyoukule.Dao" /> </mappers > </configuration >
h. 编写应用程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class App { public static void main (String[] args) throws IOException { SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder (); InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml" ); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); AccountDao accountDao = sqlSession.getMapper(AccountDao.class); Account ac = accountDao.findById(1 ); System.out.println(ac); sqlSession.close(); } }
i. 运行程序
结果为 null 是因为数据库还未插入数据。
整合思路分析
Mybatis 的基础环境我们已经准备好了,接下来就得分析下在上述的内容中,哪些对象可以交给 Spring 来管理?
2. Spring整合Mybatis 前面我们已经分析了 Spring 与 Mybatis 的整合,大体需要做两件事:
Spring 要管理 MyBatis 中的 SqlSessionFactory
Spring 要管理 Mapper 接口的扫描
实现步骤
a. 项目中导入整合需要的 jar 包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.3.27</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 2.0.5</version > </dependency >
b. 创建 Spring 的主配置类
1 2 3 4 5 6 @Configuration @ComponentScan("com.muyoukule") public class SpringConfig {}
c. 创建数据源的配置类
在配置类中完成数据源的创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class JdbcConfig { @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 public DataSource dataSource () { DruidDataSource ds = new DruidDataSource (); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; } }
d. 主配置类中读 properties
并引入数据源配置类
1 2 3 4 5 6 @Configuration @ComponentScan("com.muyoukule") @PropertySource("classpath:jdbc.properties") @Import(JdbcConfig.class) public class SpringConfig {}
e. 创建 Mybatis 配置类并配置 SqlSessionFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class MybatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactory (DataSource dataSource) { SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean (); ssfb.setTypeAliasesPackage("com.muyoukule.Entity" ); ssfb.setDataSource(dataSource); return ssfb; } @Bean public MapperScannerConfigurer mapperScannerConfigurer () { MapperScannerConfigurer msc = new MapperScannerConfigurer (); msc.setBasePackage("com.muyoukule.Dao" ); return msc; } }
说明:
f. 主配置类中引入 Mybatis 配置类
1 2 3 4 5 6 @Configuration @ComponentScan("com.muyoukule") @PropertySource("classpath:jdbc.properties") @Import({JdbcConfig.class, MybatisConfig.class}) public class SpringConfig {}
g. 编写运行类
在运行类中,从 IOC 容器中获取 Service 对象,调用方法获取结果
1 2 3 4 5 6 7 8 9 10 11 12 public class App2 { public static void main (String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext (SpringConfig.class); AccountService accountService = ctx.getBean(AccountService.class); Account tom = new Account (1 , "Tom" , 1000.00 ); accountService.save(tom); Account ac = accountService.findById(1 ); System.out.println(ac); } }
h. 运行程序
1 Account(id=1, name=Tom, money=1000.0)
Spring整合Junit 整合 Junit 与整合 Druid 和 MyBatis 差异比较大,为什么呢?Junit是一个搞单元测试用的工具,它不是我们程序的主体,也不会参加最终程序的运行,从作用上来说就和之前的东西不一样,它不是做功能的,看做是一个辅助工具就可以了。
环境准备
这块环境,大家可以直接使用 Spring 与 Mybatis 整合的环境即可。当然也可以重新创建一个。
整合Junit
a. 引入依赖
pom.xml
1 2 3 4 5 6 7 8 9 10 11 <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.13.2</version > <scope > test</scope > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-test</artifactId > <version > 5.3.27</version > </dependency >
b. 编写测试类
在 test\java下创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {SpringConfig.class}) public class AccountServiceTest { @Autowired private AccountService accountService; @Test public void testFindById () { System.out.println(accountService.findById(1 )); } @Test public void testFindAll () { System.out.println(accountService.findAll()); } }
1 2 [Account(id=1, name=Tom, money=1000.0)] Account(id=1, name=Tom, money=1000.0)
注意:
单元测试,如果测试的是注解配置类,则使用@ContextConfiguration(classes = 配置类.class)
单元测试,如果测试的是配置文件,则使用@ContextConfiguration(locations={配置文件名,...})
Junit运行后是基于 Spring 环境运行的,所以 Spring 提供了一个专用的类运行器,这个务必要设置,这个类运行器就在 Spring 的测试专用包中提供的,导入的坐标就是这个东西SpringJUnit4ClassRunner
上面两个配置都是固定格式,当需要测试哪个 bean 时,使用自动装配加载对应的对象,下面的工作就和以前做 Junit 单元测试完全一样了。