一、JDBC
JDBC(Java Data Base Connectivity)是一种用于执行SQL语句的Java API规范,可以为多种关系数据库提供统一访问,屏蔽了各种数据库API调用的差异,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
直接在Java程序中使用JDBC比较复杂,需要7步才能完成数据库的操作:加载数据库驱动
建立数据库连接
创建数据库操作对象
定义操作的SQL语句
执行数据库操作
获取并操作结果集
关闭对象,回收资源
代码:
try
{
// 1、加载数据库驱动 Class.forName(driver);
// 2、获取数据库连接 conn = DriverManager.getConnection(url, username, password);
// 3、获取数据库操作对象 stmt = conn.createStatement();
// 4、定义操作的SQL语句 String sql = "select * from user where id = 6";
// 5、执行数据库操作 rs = stmt.executeQuery(sql);
// 6、获取并操作结果集 while (rs.next())
{
// 解析结果集 }
}
catch (Exception e)
{
// 日誌信息}
finally
{
// 7、關閉資源}
通过上面的代码可以看出直接使用JDBC来操作数据库比较复杂,因此后期在JDBC的基础上又发展出了很多著名的ORM框架,其中最为流行的是Hibernate、MyBatis。JPA和MyBatis已经在之前进行了总结,工作中使用的也很多,但是以前写case时,也用过Spring JDBC Template,Spring Boot也对其进行了集成,提供了spring-boot-starter-jdbc,Spring JDBC Template是在Spring JDBC上做了进一步的封装,方便在Spring Boot生态中更好的使用。
二、Spring JDBC Template
A、相关依赖
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
B、数据源配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://10.255.242.168:3306/jdbc_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8
spring.datasource.username=_root
spring.datasource.password=Root@123
在SpringBoot 2.1.x中,com.mysql.jdbc.Driver已经过期,需要使用com.mysql.cj.jdbc.Driver作为驱动名。
C、entity实体类
@Getter
@Setter
public class User
{
private Long id;
private String name;
private String password;
private int age;
public User()
{
}
public User(String name, String password, int age)
{
this.name = name;
this.password = password;
this.age = age;
}
public User(String name, String password)
{
this.name = name;
this.password = password;
this.age = 0;
}
}
D、数据表
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`name` varchar(64) DEFAULT NULL COMMENT '用户名',
`password` varchar(64) DEFAULT NULL COMMENT '密码',
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
E、封装Repository
创建UserRepository定义常用的增删改查接口。
public interface UserRepository
{
int save(User user);
int update(User user);
int delete(Long id);
List findALL();
User findById(Long id);
}
实现类上使用@Repository注解用于标注数据访问组件,同时在类中注入JdbcTemplate,其是Spring操作JDBC提供的工具类。
@Repository
public class UserRepositoryImpl implements UserRepository
{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int save(User user)
{
return jdbcTemplate.update("INSERT INTO user(name, password, age) values(?, ?, ?)", user.getName(), user.getPassword(), user.getAge());
}
@Override
public int update(User user)
{
return jdbcTemplate.update("UPDATE user SET name = ? , password = ? , age = ? WHERE id=?", user.getName(), user.getPassword(), user.getAge(), user.getId());
}
@Override
public int delete(Long id)
{
return jdbcTemplate.update("DELETE FROM user where id = ? ", id);
}
@Override
public User findById(Long id)
{
return jdbcTemplate.queryForObject("SELECT * FROM user WHERE id=?", new Object[]{id}, new BeanPropertyRowMapper(User.class));
}
@Override
public List findALL()
{
// return jdbcTemplate.query("SELECT * FROM user", new BeanPropertyRowMapper(User.class)); return jdbcTemplate.query("SELECT * FROM user", new UserRowMapper());
}
class UserRowMapper implements RowMapper
{
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException
{
User user = new User();
user.setId(rs.getLong("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
user.setAge(rs.getInt("age"));
return user;
}
}
}
findALL()使用了一个新的方式来封装结果集的返回,创建一个内部类UserRowMapper。
UserRowMapper继承了RowMapper,RowMapper可以将数据中的每一行数据封装成用户定义的类,实现RowMapper接口覆盖mapRow方法,在mapRow方法封装对数据的返回处理。
通过代码可以看出UserRowMapper循环遍历了查询返回的结果集,遍历的同时按照属性进行赋值。这样在查询使用时只需要传入new UserRowMapper()即可自动解析返回数据。
F、测试
@Slf4j
public class UserRepositoryTest extends JdbcTemplateApplicationTests
{
@Autowired
private UserRepository userRepository;
@Test
public void testSave()
{
User user = new User("isisiwish", "pass", 18);
userRepository.save(user);
}
@Test
public void testUpdate()
{
User user = new User("cfish", "pass", 12);
user.setId(1L);
userRepository.update(user);
}
@Test
public void testDetele()
{
userRepository.delete(1L);
}
@Test
public void testQueryOne()
{
User user = userRepository.findById(2L);
log.info("{}", JSON.toJSONString(user));
}
@Test
public void testQueryAll()
{
List users = userRepository.findALL();
for (User user : users)
{
log.info("{}", JSON.toJSONString(user));
}
}
}
三、多数据源
在项目中使用多个数据源是很常见的情况,Spring Boot中多数据源的使用需要自行封装。
A、配置文件
spring.datasource.primary.jdbc-url=jdbc:mysql://10.255.242.168:3306/jdbc_db_0?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8
spring.datasource.primary.username=_root
spring.datasource.primary.password=Root@123
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.secondary.jdbc-url=jdbc:mysql://10.255.242.168:3306/jdbc_db_1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8
spring.datasource.secondary.username=_root
spring.datasource.secondary.password=Root@123
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
添加两个数据源,一个是jdbc_db_0库,一个是jdbc_db_1库。
B、数据源配置
@Configuration
public class DataSourceConfig
{
@Primary
@Bean(name = "primaryDataSource")
@Qualifier("primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource()
{
return DataSourceBuilder.create().build();
}
@Bean(name = "secondaryDataSource")
@Qualifier("secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource()
{
return DataSourceBuilder.create().build();
}
@Bean(name = "primaryJdbcTemplate")
public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource dataSource)
{
return new JdbcTemplate(dataSource);
}
@Bean(name = "secondaryJdbcTemplate")
public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource dataSource)
{
return new JdbcTemplate(dataSource);
}
}
启动时根据特定的前缀加载不同的数据源,根据构建好的数据源再创建不同的JDBC。
C、UserRepository改造
public interface UserRepository
{
int save(User user, JdbcTemplate jdbcTemplate);
int update(User user, JdbcTemplate jdbcTemplate);
int delete(Long id, JdbcTemplate jdbcTemplate);
List findALL(JdbcTemplate jdbcTemplate);
User findById(Long id, JdbcTemplate jdbcTemplate);
}
@Repository
public class UserRepositoryImpl implements UserRepository
{
@Autowired
private JdbcTemplate primaryJdbcTemplate;
@Override
public int save(User user, JdbcTemplate jdbcTemplate)
{
if (jdbcTemplate == null)
{
jdbcTemplate = primaryJdbcTemplate;
}
return jdbcTemplate.update("INSERT INTO user(name, password, age) values(?, ?, ?)", user.getName(), user.getPassword(), user.getAge());
}
}
D、多数据源测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class JdbcTemplateMultiApplicationTests
{
@Autowired
private UserRepository userRepository;
@Autowired
private JdbcTemplate primaryJdbcTemplate;
@Autowired
private JdbcTemplate secondaryJdbcTemplate;
@Test
public void testSave()
{
User user = new User("isisiwish", "password", 18);
userRepository.save(user, primaryJdbcTemplate);
userRepository.save(user, secondaryJdbcTemplate);
}
}