学习视频:9001 JdbcTemplate概述_哔哩哔哩_bilibili~9010 案例:实现用户登录_哔哩哔哩_bilibili
目录
1.Spring JDBC
1.1JDBCTemplate概述
JDBCTemplate作用
针对数据库操作,Spring框架提供了JdbcTemplate类,JdbcTemplate是一个模板类,Spring JDBC中的更高层次的抽象类均在JdbcTemplate模板类的基础上创建。 JdbcTemplate类提供了操作数据库的基本方法,包括添加、删除、查询和更新。在操作数据库时,JdbcTemplate类简化了传统JDBC中的复杂步骤,这可以让开发人员将更多精力投入到业务逻辑中。
抽象类JdbcAccessor的属性
JdbcTemplate类继承自抽象类JdbcAccessor,同时实现了JdbcTemplate接口。抽象类JdbcAccessor提供了一些访问数据库时使用的公共属性,具体如下:
DataSource:DataSource主要功能是获取数据库连接。在具体的数据操作中,它还提供对数据库连接的缓冲池和分布式事务的支持。
SQLExceptionTranslator:SQLExceptionTranslator是一个接口,它负责对SQLException异常进行转译工作。
1.2Spring JDBC的配置
Spring JDBC中的4个包说明
<!-- 1.配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 数据库驱动 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!-- 连接数据库url -->
<property name="url" value="jdbc:mysql://localhost:3306/spring"/>
<property name="username" value="root"/><!-- 连接数据库用户名 -->
<property name="password" value="root"/><!-- 连接数据库密码 -->
</bean>
<!-- 2.配置JDBC模板 -->
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 3.配置注入类 -->
<bean id="xxx" class="Xxx"> <property name="JdbcTemplate" ref="JdbcTemplate"/></bean>
dataSource配置4个属性的含义
dataSource属性值的设定要求
在dataSource的4个属性中,需要根据数据库类型或者系统配置设置相应的属性值。例如,如果数据库类型不同,需要更改驱动名称;如果数据库不在本地,则需要将地址中的localhost替换成相应的主机IP;默认情况下,数据库端口号可以省略,但如果修改过MySQL数据库的端口号,则需要加上修改后的端口号。此外,连接数据库的用户名和密码需要与数据库创建时设置的用户名和密码保持一致。
代码实现
public class UserDaoImpl {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public JdbcTemplate getJdbcTemplate() {
return 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"
xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.it"></context:component-scan>
<!-- 定义数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="userDao" class="com.it.demo01.UserDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"> </property>
</bean>
</beans>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class JdbcTemplateTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDaoImpl userDao=(UserDaoImpl) context.getBean("userDao");
System.out.println(userDao.getJdbcTemplate());
}
}
2.JDBCTemplate的常用方法
execute()方法用于执行SQL语句,其语法格式如下:
jdTemplate.execute("SQL 语句");
<!-- 定义数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
public class JdbcTemplateTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
/* UserDaoImpl userDao=(UserDaoImpl) context.getBean("userDao");
System.out.println(userDao.getJdbcTemplate());*/
JdbcTemplate jdbcTemplate=(JdbcTemplate)context.getBean("jdbcTemplate");
jdbcTemplate.execute("create table account(" +
"id int primary key auto_increment," +
"username varchar(50)," + "balance double)");
System.out.println("account表创建成功");
}
}
update()方法
先插入数据insert
public interface AccountDao {
public Integer add(Account account);
public Integer delete(Integer id);
public Integer update(Account account);
}
import org.springframework.jdbc.core.JdbcTemplate;
public class AccountDaoImpl implements AccountDao{
private JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public Integer add(Account account) {
String sql = "insert into account(username, balance) values(?,?)";
Object[] params=new Object[]{account.getName(),account.getBalance()};
return jdbcTemplate.update(sql, params);
}
@Override
public Integer delete(Integer id) {
return 0;
}
@Override
public Integer update(Account account) {
return 0;
}
}
<bean id="accountDao" class="com.it.demo01.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
public class AccountDaoTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountDao accountDao = (AccountDao) context.getBean("accountDao");
Account account = new Account();
account.setName("tom");
account.setBalance(1000.0);
Integer num= accountDao.add(account);
if(num>0)
{
System.out.println("插入成功");
}
else {
System.out.println("插入失败");
}
}
}
update()
@Override
public Integer update(Account account) {
String sql = "update account set username=?,balance=? where id=?";
Object[]params=new Object[]{account.getName(),account.getBalance(),account.getId()};
return jdbcTemplate.update(sql, params);
}
public class AccountDaoTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountDao accountDao = (AccountDao) context.getBean("accountDao");
Account account = new Account();
account.setName("lucy");
account.setBalance(2000.0);
account.setId(1);
// Integer num= accountDao.add(account);
Integer num=accountDao.update(account);
if(num>0)
{
System.out.println("修改成功");
}
else {
System.out.println("修改失败");
}
}
}
删除delete()
@Override
public Integer delete(Integer id) {
String sql = "delete from account where id=?";
return jdbcTemplate.update(sql,id);
}
Integer num=accountDao.delete(1);
if(num>0)
{
System.out.println("删除成功");
}
else {
System.out.println("删除失败");
}
query()方法
JdbcTemplate类中常用的查询方法
查询单个
public class Account {
private Integer id;
private String username;
private double balance;
@Override
public String toString() {
return "Account{" +
"id=" + id +
", username='" + username + '\'' +
", balance=" + balance +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
@Override
public Account findAccountById(Integer id) {
String sql = "select * from account where id=?";
RowMapper<Account> rowMapper = new BeanPropertyRowMapper<Account>(Account.class);
Account account=jdbcTemplate.queryForObject(sql,rowMapper,id);
return account;
}
public class AccountDaoTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountDao accountDao = (AccountDao) context.getBean("accountDao");
Account account=accountDao.findAccountById(3);
System.out.println(account);
}
}
查询多个
@Override
public List<Account> findAllAccount() {
String sql = "select * from account";
RowMapper<Account> accountRowMapper=new BeanPropertyRowMapper<Account>(Account.class);
List<Account> accounts=jdbcTemplate.query(sql,accountRowMapper);
return accounts;
}
List<Account> accounts=accountDao.findAllAccount();
for(Account account:accounts){
System.out.println(account);
}
3.Spring的事务管理
spring-tx-5.2.8.RELEAS依赖包的3个接口
PlatformTransactionManager接口:可以根据属性管理事务。
TransactionDefinition接口:用于定义事务的属性。
TransactionStatus接口:用于界定事务的状态 。
PlatformTransactionManager接口
PlatformTransactionManager 接口主要用于管理事务,该接口中提供了三个管理事物的方法。
TransactionDefinition接口
TransactionDefinition接口中定义了事务描述相关的常量,其中包括了事务的隔离级别、事务的传播行为、事务的超时时间和是否为只读事务。
事务的隔离级别
事务的传播行为
事务的传播行为是指处于不同事务中的方法在相互调用时,方法执行期间,事务的维护情况。例如,当一个事务的方法B调用另一个事务的方法A时,可以规定A方法继续在B方法所属的现有事务中运行,也可以规定A方法开启一个新事务,在新事务中运行,B方法所属的现有事务先挂起,等A方法的新事务执行完毕后再恢复。
TransactionDefinition接口中定义的7种事务传播行为
事务的超时时间
事务的超时时间是指事务执行的时间界限,超过这个时间界限,事务将会回滚。TransactionDefinition接口提供了TIMEOUT_DEFAULT常量定义事务的超时时间。
事务是否只读
当事务为只读时,该事务不修改任何数据,只读事务有助于提升性能,如果在只读事务中修改数据,会引发异常。
TransactionDefinition接口中除了提供事务的隔离级别、事务的传播行为、事务的超时时间和是否为只读事务的常量外,还提供了一系列方法来获取事务的属性。
TransactionDefinition接口常用方法
TransactionStatus接口
事务的管理方式
Spring中的事务管理的两种方式
Spring中的事务管理分为两种方式,一种是传统的编程式事务管理,另一种是声明式事务管理。
编程式事务管理:通过编写代码实现的事务管理,包括定义事务的开始、正常执行后的事务提交和异常时的事务回滚。
声明式事务管理:通过AOP技术实现的事务管理,其主要思想是将事务管理作为一个“切面”代码单独编写,然后通过AOP技术将事务管理的“切面”代码植入到业务目标类中。
声明式事务管理
基于XML方式的声明式事务
基于XML方式的声明式事务管理是通过在配置文件中配置事务规则的相关声明来实现的。在使用XML文件配置声明式事务管理时,首先要引入tx命名空间,在引入tx命名空间之后,可以使用<tx:advice>元素来配置事务管理的通知,进而通过Spring AOP实现事务管理。 配置<tx:advice>元素时,通常需要指定 id 和 transaction-manager 属性,其中,id 属性是配置文件中的唯一标识,transaction-manager 属性用于指定事务管理器。除此之外,<tx:advice>元素还包含子元素<tx: attributes>,<tx:attributes>元素可配置多个<tx:method>子元素,<tx:method>子元素主要用于配置事务的属性。
<tx:method>元素的常用属性
不使用事务配置
@Override
public void transfer(String outUser, String inUser, Double money)
{
//收款
jdbcTemplate.update("update account set balance=balance+? where username=?",money,inUser);
//模拟异常
int i=1/0;
//付款
jdbcTemplate.update("update account set balance=balance-? where username=?",money,outUser);
}
public class TransactionTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
accountDao.transfer("李四", "张三", 100.0);
}
}
刚刚张三是200,李四是400,运行后张三的钱增加了但是李四的钱没有减少,数据不一致性
配置事务
<bean id="accountDao" class="com.it.demo01.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- xml事务配置-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"
isolation="DEFAULT" read-only="false" /></tx:attributes>
</tx:advice>
<!-- 6.编写aop,使用AspectJ的表达式,让spring自动对目标生成代理-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.it.demo01.AccountDao.*(..))"/><!--AccountDao接口下的所有方法做事务管理-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"></aop:advisor>
</aop:config>
@Override
public void transfer(String outUser, String inUser, Double money)
{
//收款
jdbcTemplate.update("update account set balance=balance+? where username=?",money,inUser);
//模拟异常
int i=1/0;
//付款
jdbcTemplate.update("update account set balance=balance-? where username=?",money,outUser);
}
public class TransactionTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
accountDao.transfer("李四", "张三", 100.0);
}
}
报by zero异常后刷新数据库张三李四的钱不变
这时候我们把模拟异常注释掉再运行,刷新后数据库中张三的钱多100,李四的少100
基于注解方式的声明式事务
@Transactional(propagation = Propagation.REQUIRED,readOnly = false,isolation = Isolation.DEFAULT)
@Override
public void transfer(String outUser, String inUser, Double money)
{
//收款
jdbcTemplate.update("update account set balance=balance+? where username=?",money,inUser);
//模拟异常
int i=1/0;
//付款
jdbcTemplate.update("update account set balance=balance-? where username=?",money,outUser);
}
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
public class TransactionTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
accountDao.transfer("李四", "张三", 100.0);
}
}
测试,数据库信息未发生变化.原因:事务生效,发生回滚
4.案例:实现用户登录
案例要求
本案例要求学生在控制台输入用户名密码,如果用户账号密码正确则显示用户所属班级,如果登录失败则显示登录失败。
数据准备
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(255),
PASSWORD VARCHAR(255),
course VARCHAR(255)
);
代码实现
public class Student {
private Integer id;
private String username;
private String password;
private String course;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", course='" + course + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
}
public interface StudentDao {
public Student findStudentByUsernameAndPassword(String username, String password);
}
public class StudentDaoImpl implements StudentDao {
private JdbcTemplate jdbcTemplate;
@Override
public Student findStudentByUsernameAndPassword(String username, String password) {
String sql = "select * from student where username=? and password=?";
Student student=null;
try {
student= jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<>(Student.class), username,password);
} catch (EmptyResultDataAccessException e) {
return null;
}
return student;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public StudentDaoImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
<!-- 定义数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=UTF-8&amp"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!-- jdbc模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="studentDao" class="com.it.dao.impl.StudentDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
public class StudentController {
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentDao studentDao=(StudentDao) applicationContext.getBean("studentDao");
//接受用户输入的对象
Scanner sc = new Scanner(System.in);
System.out.println("欢迎来到学生管理系统");
System.out.println("请输入用户名");
//接受输入
String username=sc.nextLine();
System.out.println("请输入"+username+"密码");
//接受密码
String password=sc.nextLine();
//从数据库查询
Student student=studentDao.findStudentByUsernameAndPassword(username,password);
if(student==null){
System.out.println("用户登录失败,用户名或密码错误");
}
else {
System.out.println("用户登录成功");
System.out.println(username+"是"+student.getCourse()+"班的");
}
}
}
如果添加事务的话,搞这个
<!-- 事务管理器对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启注解式声明式事务-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
然后在public Student findStudentByUsernameAndPassword(String username,String password)上方加@Transactional()注解即可