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

    技术2026-04-13  6

    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); }
    Processed: 0.019, SQL: 9