五通用支持」」Spring中配置JDBC

2.JDBC支持

2-1 使用JdbcTemplate
包含插入并返回主键的实现

将JdbcTemplate注入给对应的dao

将dataSource注入给JdbcTemplate

1.设置dataSources.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/ums?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=

2.配置spring.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: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 https://www.springframework.org/schema/context/spring-context.xsd">
  
	<!--
 		载入dataSources.properties
  		classpath:最好写上,不写大的项目中可能出错
	-->		
    <context:property-placeholder location="classpath:dataSource.properties"/>
	
  
  	<!--
 		配置数据源的二种方式
	-->	
    <!-- 方式一 : 使用Spring内置的 -->
    <!--<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">-->
        <!--<property name="driverClassName" value="${jdbc.driver}"/>-->
        <!--<property name="url" value="${jdbc.url}"/>-->
        <!--<property name="username" value="${jdbc.username}"/>-->
        <!--<property name="password" value="${jdbc.password}"/>-->
    <!--</bean>-->

    <!-- 方式二 :  使用第三方的BasicDataSource -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <!-- 最大连接数 -->
        <property name="maxActive" value="1"/>
        <!-- 初始化连接数 -->
        <property name="initialSize" value="1"/>
        <!-- 
				最长等待时间 
				如果在等待时间没有取到连接会出现报错
				等待时间单位毫秒
		-->
        <property name="maxWait" value="3000"/>
    </bean>
    <!-- 配置JDBCTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 
		配置UserDao
 		在UserDao的实现类UserDaoImpl中需要设置JdbcTemplate属性
		所以需要在实现类中设设置属性属性
	-->
    <bean id="userDao" class="dao.impl.UserDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
</beans>

3.dao层的接口和实现类的设置

接口UserDao

import entity.User;

import java.util.List;

public interface UserDao {
    public void insertUser(User user);
    public void deleteUser(Integer id);
    public void updateUser(User user);
    public User selectById(Integer id);
    public List<User> selectAll();
    public Long insertReturnPrimaryKey(User user);
}

实现类UserDaoImpl

package dao.impl;

import dao.UserDao;
import entity.User;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;

public class UserDaoImpl implements UserDao {
   //在实现类中JdbcTemplate设置属性
    private JdbcTemplate jdbcTemplate;
   //实现set方法
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    @Override
    public void insertUser(User user) {
        String sql = new StringBuffer()
                .append(" insert into ")
                .append(" t_user ")
                .append("   (username,password,phone,address)")
                .append(" values ")
                .append("   (?,?,?,?)")
                .toString();
        jdbcTemplate.update(sql,user.getUsername(),user.getPassword(),user.getPhone(),user.getAddress());
    }
  
  
	@Override
    public User selectById(Integer id) {
        String sql = new StringBuffer()
                .append(" select id,username,password,phone,address ")
                .append(" from t_user ")
                .append(" where id = ? ")
                .toString();
      //关于结果集行处理可以实现匿名实现也可以单独写一个类处理2
        List<User> users = jdbcTemplate.query(sql,new UserRowMapper(),id);
        return users.isEmpty()?null:users.get(0);
    }
  
  
    /**
    *jdbc中的返回主键,在做购物车业务时需要
    **/
    @Override
    public Long insertReturnPrimaryKey(User user) {
        KeyHolder keyHolder = new GeneratedKeyHolder();
        jdbcTemplate.update(new PreparedStatementCreator() {
            @Override
            public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
                String sql = new StringBuffer()
                        .append(" insert into ")
                        .append(" t_user ")
                        .append("   (username,password,phone,address)")
                        .append(" values ")
                        .append("   (?,?,?,?)")
                        .toString();
                PreparedStatement ps = con.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);
                ps.setString(1,user.getUsername());
                ps.setString(2,user.getPassword());
                ps.setString(3,user.getPhone());
                ps.setString(4,user.getAddress());
                return ps;
            }
        },keyHolder);
        return (Long) keyHolder.getKey();
    }
}

4.测试

public class Test02 {

   public static void main(String[] args) {
       ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
//        UserDao userDao = (UserDao) ac.getBean("userDao");
       UserDao userDao = (UserDao) ac.getBean("userDao2");
       User user = new User();
       user.setUsername("tom");
       user.setPassword("123456");
       user.setPhone("13912345678");
       user.setAddress("江苏-南京");
//        userDao.insertUser(user);

       Long primaryKey = userDao.insertReturnPrimaryKey(user);

       System.out.println("返回的主键为:"+primaryKey);

   }

}


2-2 使用JdbcDaoSupport

Spring定义一个JdbcDaoSupport类

该类是作为所有dao的父类而存在的

该类中注入了JdbcTemplate模板类

在具体dao中继承了JdbcDaoSupport之后

可以通过getJdbcTemplate的方法直接获取模板类

由于dataSource是由开发者定义的

因此,我们可以直接在具体的dao中注入dataSource的值即可

<!--
 		载入dataSources.properties
  		classpath:最好写上,不写大的项目中可能出错
	-->		
    <context:property-placeholder location="classpath:dataSource.properties"/>
	
    <!-- 方式二 :  使用第三方的BasicDataSource -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <!-- 最大连接数 -->
        <property name="maxActive" value="1"/>
        <!-- 初始化连接数 -->
        <property name="initialSize" value="1"/>
        <!-- 
				最长等待时间 
				如果在等待时间没有取到连接会出现报错
				等待时间单位毫秒
		-->
        <property name="maxWait" value="3000"/>
    </bean>

    <!-- 配置UserDao -->
    <bean id="userDao" class="dao.impl.UserDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
 <!--
 	JdbcDaoSupport与配置JDBCTemplate不同
 	JdbcDaoSupport定义为所有dao的父类
	所以直接注入就可以了
-->
  <bean id="userDao2" class="dao.impl.UserDaoImpl2">
    <property name="dataSource" ref="dataSource"/>
</bean>
</beans>

//继承父类JdbcDaoSupport 直接注入getJdbcTemplate()方法.十分简单方便
public class UserDaoImpl2 extends JdbcDaoSupport implements UserDao {

    @Override
    public User selectById(Integer id) {
        String sql = new StringBuffer()
                .append(" select id,username,password,phone,address ")
                .append(" from t_user ")
                .append(" where id = ? ")
                .toString();
        List<User> users = getJdbcTemplate().query(sql,new UserRowMapper(),id);
        return users.isEmpty()?null:users.get(0);
    }
}
2.3jdbc行处理

import com.shoppingMVC.entity.Product;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
*这是一个产品的行处理
*需要实现结果集中的RowMapper接口
*返回对象
**/
public class ProductMapper implements RowMapper<Product> {
    @Override
    public Product mapperRow(ResultSet rs) throws SQLException {
        Product p = new Product(
            rs.getInt("id"),
            rs.getString("name"),
            rs.getDouble("price"),
            rs.getString("image"),
            rs.getString("info"),
            rs.getInt("status")
        );
        return p;
    }
}

3.MyBatis支持

3-1 POM配置
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.3</version>
</dependency>
3-2 配置文件

1.UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.UserDao">
    <sql id="userColumn">
        id,
        username,
        password,
        phone,
        address
    </sql>
<!-- 
	Spring中通过扫包设置了别名
	resultType中可以直接写别名就可以 
	如果没有设置需要写相对路径Entity.User
-->
    <select id="selectAll" resultType="User">
        select <include refid="userColumn"></include>
        from t_user
    </select>

    <insert id="insertUser" parameterType="User">
        insert into
        t_user
          (username,password,phone,address)
        values
          (#{username},#{password},#{phone},#{address})
    </insert>
    
</mapper>

2.mybatis-config.xml

<?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>
<!--
sqlSessionFactory中整合了mybatis-config的配置
但是mybatis-config的插件任然可以被使用
-->
    <typeAliases></typeAliases>
    <mappers></mappers>

</configuration>

3.spring.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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
  
	<!-- 读取propert配置文件 -->
    <context:property-placeholder location="classpath:dataSource.properties"/>
	<!-- 设置数据源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- sqlSessionFactory中整合了mybatis-config的配置 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入数据源 -->
        <property name="dataSource" ref="dataSource"/>
      
        <!-- 配置别名  扫包,在mapper中都可以直接使用类名-->
        <property name="typeAliasesPackage" value="entity"/>
      
        <!-- 注册mapper -->
        <property name="mapperLocations">
            <list>
                <!--<value>classpath:mapper/UserMapper.xml</value>-->
                <!-- 支持通配符 -->
                <value>classpath:mapper/*.xml</value>
            </list>
        </property>
        <!-- 访问config配置 -->
        <!--<property name="configLocation" value="classpath:mybatis-config.xml"/>-->
    </bean>

    <!-- 配置UserDao -->
    <!-- 方式一:使用MapperFactoryBean生产对应的Mapper -->
    <!--<bean id="userDao" class="org.mybatis.spring.mapper.MapperFactoryBean">-->
        <!--&lt;!&ndash; 注入SqlSessionFactory &ndash;&gt;-->
        <!--<property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
        <!--&lt;!&ndash; 配置需要生产的接口是谁 &ndash;&gt;-->
        <!--<property name="mapperInterface" value="dao.UserDao"/>-->
    <!--</bean>-->

    <!--
        方式二:使用扫包的方式创建指定包下所有的Mapper
        使用后处理bean对当前的工程做整体的操作
        会自动扫描指定包下所有的接口
        实现对这些接口的Mapper生产
        生产出来的所有的Mapper其bean的id即为当前类名,首字母小写
     -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="dao"/>
    </bean>

    <!-- 事务配置 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入数据源 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- AOP2.X注解事务 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <context:component-scan base-package="service"/>

</beans>
3-3 测试
package test;

import entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;

/**
 * Author:shixiaojun@itany.com
 * Date:2020/7/3-9:29
 */
public class Test {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring.xml");


        // 方式一:使用MyBatis原始方式
//        SqlSessionFactory factory = (SqlSessionFactory) ac.getBean("sqlSessionFactory");
//        SqlSession session = factory.openSession();
//        UserDao userDao = session.getMapper(UserDao.class);

        // 方式二:使用MapperFactoryBean获取对应的Mapper
//        UserDao userDao = (UserDao) ac.getBean("userDao");

        // 方式三:使用扫包方式进行操作,bean的id为类名首字母小写
//        UserDao userDao = (UserDao) ac.getBean("userDao");
//        List<User> users = userDao.selectAll();
//        for(User user : users){
//            System.out.println(user);
//        }

        User user = new User();
        user.setUsername("test4");
        user.setPassword("666666");
        user.setPhone("13945121238");
        user.setAddress("江苏-南京");
//
//        userDao.insertUser(user);


        UserService userService = (UserService) ac.getBean("userServiceImpl");
        System.out.println(userService);
        userService.regist(user);

    }

}

4.事务支持

4-1 什么是事务

所谓的事务,表示一次不可再分的操作序列

这些操作序列中的所有操作

要么都执行,要么都不执行

它是一个不可分割的完整的工作单元

4-2 传统数据库的事务特性

ACID

  • A
    • Atomicity
    • 原子性
  • C
    • Consistency
    • 一致性
  • I
    • Isolation
    • 隔离性
  • D
    • Durability
    • 持久性
4-3 Spring事务特性
  • 传播行为
    • 在Spring中,传播的规则有很多,一般需要熟练掌握其中两种
    • REQUIRED
      • 表示当前的方法必须运行在一个存在事务管理的环境中
      • 在运行时会判断当前的环境中是否存在事务管理
        • 如果存在,则会自动加入到当前的事务管理中
        • 如果不存在,则会开启一个新的事务环境用于执行当前的业务
      • 一般用于增删改操作
    • SUPPORTS
      • 表示当前的方法不是必须运行在事务管理的环境中
      • 有事务可以运行,没有事务也可以运行
      • 在运行时会判断当前的环境中是否存在事务管理
        • 如果存在,则会自动加入到当前的事务管理中
        • 如果不存在,则拉倒
      • 一般用于查询操作
      • 一般不会单独使用,会与其他属性联合使用
  • 回滚条件
    • 默认情况下,当遇到RuntimeException以及其子类的时候,会自动回滚
    • 可以进行手动设置
      • rollbackFor="异常的class类型"
        • 表示遇到指定的异常会进行回滚
      • noRollbackFor="异常的class类型"
        • 表示遇到指定的异常不进行回滚
  • 只读优化
    • 当你确定你的业务中有且仅有查询操作时才能使用
    • readOnly=true
    • 一般与传播规则的SUPPORTS联合使用
  • 超时
    • Timeout
  • 隔离级别
    • 从小到大
    • TRANSACTION_NONE
      • 指示事务不受支持的常量
      • 即没有事务
    • TRANSACTION_READ_UNCOMMITTED
      • 指示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量。
      • 即读未提交数据
    • TRANSACTION_READ_COMMITTED
      • 指示不可以发生脏读的常量;不可重复读和虚读可以发生。
      • 即读已提交数据
    • TRANSACTION_REPEATABLE_READ
      • 指示不可以发生脏读和不可重复读的常量;虚读可以发生。
      • 大部分的数据库均未对该级别做实现
      • MySql与Oracle均未实现
    • TRANSACTION_SERIALIZABLE
      • 指示不可以发生脏读、不可重复读和虚读的常量。
      • 解决了并发
      • 但是产生了悲观锁的问题
4-4 POM配置
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>${spring.version}</version>
</dependency>
4-5 Spring配置

以注解事务为例

Spring整合JDBC与MyBatis使用的是相同的事务管理器

DataSourceTransactionManager

<context:component-scan base-package="service"/>
<!-- 事务配置 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置AOP2.X注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
4-6 注解使用
  • @Transactional
    • 表示配置事务的相关操作
    • 该注解可以标注在类上,也可以标注在方法上
    • 该注解标注在类上表示当前类均使用此时进行的事务配置
    • 该注解标注在方法上表示当前方法使用此时进行的实物配置
    • 如果类上与方法上均有该注解,优先使用方法上的事务配置
  • propagation属性
    • 配置传播规则的事务属性
    • 其值是一个枚举类型,使用Propagation中提供的值
    • 其值一般使用REQUIRED或者SUPPOTRS
  • rollbackFor属性
    • 配置回滚条件
    • 当遇到指定的异常时进行回滚
  • noRollbackFor属性
    • 配置回滚条件
    • 当遇到指定的异常时不进行回滚
  • readOnly=true
    • 配置是否只读
    • 当操作中有且仅有查询操作时使用
@Service

@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class,noRollbackFor = ArithmeticException.class)
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public void regist(User user) throws UserExistException {
        UserExample example = new UserExample();
        example.or()
                .andUsernameEqualTo(user.getUsername());
        List<User> users = userMapper.selectByExample(example);
        if(!users.isEmpty()){
            throw new UserExistException("该用户已经被注册");
        }
        userMapper.insertSelective(user);
        int i = 1/0;
    }

    @Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
    @Override
    public User login(String username, String password) throws UserNotExistException {
        UserExample example = new UserExample();
        example.or()
                .andUsernameEqualTo(username)
                .andPasswordEqualTo(password);
        List<User> users = userMapper.selectByExample(example);
        if(users.isEmpty()){
            throw new UserNotExistException("用户名或密码错误");
        }
        return users.get(0);
    }
}

5.web支持

5-1 POM配置
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
</dependency>

<!-- J2EE 环境依赖 begin -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.1</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
<!-- J2EE 环境依赖 end -->
5-2 tomcat插件
<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
        <!-- 配置应用名,在Maven开发中,一般配置空就行 -->
        <path>/</path>
        <!-- 配置端口号 -->
        <port>8080</port>
    </configuration>
</plugin>
5-3 配置监听器

配置Application创建销毁事件的一个监听器

用于在服务器启动的时候解析Spring容器

该监听器由Spring提供,我们需要对其进行配置即可

Spring提供的监听器为:ContenxtLoaderListener

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

但是,由于Spring的容器是由开发者定义的

Spring无法预先知道我们的配置文件放在哪

因此,提供了一个全局初始化参数,用于指定容器的位置

该参数的key为contextConfigLocation

通过全局初始化对该参数值可以配置

<!-- 配置全局初始化参数,用于指定Spring配置文件的位置 -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <!-- 初始化参数的值支持通配符 -->
    <!--<param-value>classpath:applicationContext.xml</param-value>-->
    <param-value>classpath:applicationContext*.xml</param-value>
</context-param>
5-4 UserServlet
WebApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
UserService userService = (UserService) ac.getBean("userServiceImpl");
String username = request.getParameter("username");
String password = request.getParameter("password");

try {
    User user = userService.login(username, password);
    request.getSession().setAttribute("user", user);
    response.sendRedirect(request.getContextPath() + "/regist.jsp");
} catch (UserNotExistException e) {
    request.setAttribute("loginMsg", e.getMessage());
    request.getRequestDispatcher("/login.jsp").forward(request, response);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值