Spring+SpringMvc解决事务无效问题

本文详细解析了Spring框架中事务配置的常见问题及解决方案,重点介绍了如何正确配置事务管理器及AOP切点,确保业务逻辑能够正确地被事务管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近做课设,发现我的service层配置的事务没有效果,首先排查就是就是application-transcation.xml 配置的事务如下:

<!-- 事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 通知 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="save*" propagation="REQUIRED" />
			<tx:method name="update*" propagation="REQUIRED" />
			<tx:method name="delete*" propagation="REQUIRED" />
			<tx:method name="insert*" propagation="REQUIRED" />
			<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
			<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
		</tx:attributes>
	</tx:advice>
	<!-- 切面 -->
	<aop:config>
		<aop:pointcut id="services"
			expression="execution(* com.gongyexueyuan.service.*.*(..))" />
		<aop:advisor pointcut-ref="services" advice-ref="txAdvice" />
	</aop:config>
也没有错误 但是通过查阅资料发现我的Springmvc.xml扫面是这样的:<context:component-scan base-package="com.gongyexueyuan" ></context:component-scan>  原因就是因为我通过注解扫描后率先生成Bean 扫描 @Component,  @Repository, @Service, or @Controller 以及@Autowired j接着才会加载事务配置文件 这时候事务对提前生成的对象没有作用了。所以扫描service 要在事务中生成对象这时候就需要使用
<!--
base-package   这个需要注意 因为这个配置作用是指扫描@Controller 当你写的不只是controller包的时候就需要加上
use-default-filters="false"
当你写到
com.gongyexueyuan.controller 可以不写


>

<context:component-scan base-package="com.gongyexueyuan" use-default-filters="false">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan> 
<context:component-scan base-package="com.gongyexueyuan.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>

这时候还不可以因为这只是在加载spingmvc生成有@Controller注解的类,其他还没有比如@service 以及@Repository 等这时候就需要在application-transcation.xml配置扫描包如下:
<context:component-scan base-package="com.gongyexueyuan" >
	<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan> 
这个配置是除了带有@Controller 失效其他有效。这时生成的对象就加上事务控制了。

到此由于扫描包引起的事务失效得到解决。失效事务原因还有,这只是其中一种,以后望大家多多分享心得.


<think>我们正在构建一个基于Spring+SpringMVC+MyBatis+Vue的前后端分离电影院购票系统。技术栈包括:JDK8、Tomcat8.5、Node.js20+、MySQL5.x。项目架构设计将采用经典的三层架构(表现层、业务逻辑层、数据访问层),前后端分离,前端通过Vue框架构建,后端使用Spring+SpringMVC+MyBatis(SSM)框架。数据库设计需要满足电影院购票业务的需求,包括用户、电影、场次、座位、订单等核心实体。下面我将从以下几个方面进行详细设计:1.项目架构设计2.技术选型3.数据库设计一、项目架构设计整个系统采用前后端分离架构,前端与后端通过RESTfulAPI进行通信。后端架构分层:-表现层(Controller):SpringMVC框架,接收HTTP请求,调用服务层,返回JSON数据。-业务逻辑层(Service):实现业务逻辑,事务控制在此层。-数据访问层(Mapper/Dao):MyBatis框架,操作数据库。前端架构:-Vue框架,使用VueCLI构建项目,采用VueRouter进行路由管理,Vuex进行状态管理,Axios进行HTTP请求。模块划分:-用户模块:注册、登录、个人信息管理-电影模块:电影列表、电影详情-场次模块:根据日期、电影查询场次,场次座位信息-订单模块:下单、支付(模拟)、订单查询-后台管理模块(可选):电影管理、场次管理、订单管理等二、技术选型1.后端技术栈:-JDK8-Tomcat8.5(作为Servlet容器)-Spring4.x(Spring框架核心,包括IoC、AOP等)-SpringMVC4.x(Web层框架)-MyBatis3.x(持久层框架)-MySQL5.x(数据库)-Druid(数据库连接池)-Jackson(JSON处理)-Maven(项目构建管理)2.前端技术栈:-Node.js20+(运行环境)-Vue2/3(前端框架)-VueRouter(路由管理)-Vuex(状态管理)-Axios(HTTP客户端)-ElementUI(UI组件库,也可选择其他如AntDesignVue)3.开发工具:-IDE:IntelliJIDEA(后端)、VSCode(前端)-数据库管理工具:Navicat或MySQLWorkbench4.其他:-版本控制:Git-API文档:Swagger(可选,用于后端API文档生成)三、数据库设计数据库名为:cinema_db主要表设计:1.用户表(user)-id:主键,自增-username:用户名,唯一-password:密码(存储加密后的字符串)-email:邮箱-phone:手机号-create_time:创建时间-update_time:更新时间2.电影表(movie)-id:主键,自增-name:电影名称-director:导演-actors:主演-duration:时长(分钟)-description:简介-poster:海报URL-release_date:上映日期-status:状态(0:未上映,1:上映中,2:已下映)3.放映厅表(hall)-id:主键,自增-name:放映厅名称-seats_layout:座位布局(例如:10排10座,存储为行数和列数)-description:描述4.场次表(schedule)-id:主键,自增-movie_id:电影id(外键)-hall_id:放映厅id(外键)-start_time:放映开始时间-end_time:放映结束时间(可通过电影时长+开始时间计算)-price:票价5.座位表(seat)-id:主键,自增-schedule_id:场次id(外键)-row:行号-col:列号-status:状态(0:可选,1:已售,2:锁定)6.订单表(order)-id:主键,自增-user_id:用户id(外键)-schedule_id:场次id(外键)-total_amount:总金额-status:订单状态(0:待支付,1:已支付,2:已取消,3:已完成)-create_time:创建时间-update_time:更新时间7.订单明细表(order_item)-id:主键,自增-order_id:订单id(外键)-seat_id:座位id(外键)-price:购买时的单价注意:订单和订单明细是一对多关系,一个订单可以包含多个座位(多张票)。四、后端项目结构(Maven项目)src/main/java├──com.cinema│├──controller#控制器层│├──service#服务层接口││└──impl#服务层实现│├──dao#数据访问层接口(Mapper接口)│├──entity#实体类│├──dto#数据传输对象│├──util#工具类│└──config#配置类(如MyBatis配置Spring配置等)src/main/resources├──mapper#MyBatis的XML映射文件├──application.properties#Spring配置文件└──mybatis-config.xml#MyBatis全局配置文件(可选)五、前端项目结构(Vue项目)src├──api#封装API请求├──assets#静态资源├──components#公共组件├──router#路由配置├──store#Vuex状态管理├──views#页面视图├──App.vue#根组件└──main.js#入口文件六、关键实现点1.跨域问题:前后端分离部署时,前端通过代理或后端配置CORS解决跨域。2.用户认证:使用JWT(JSONWebToken)进行用户认证,用户登录后返回token,后续请求在HTTP头部携带token。3.选座逻辑:用户选座时,后端需要处理座位的锁定(防止并发),可以使用数据库乐观锁或Redis分布式锁。4.订单超时:用户选座后生成订单,但未支付,需要设置超时时间(如15分钟),超时后释放座位。可通过定时任务实现。七、部署后端:使用Maven打包成war包,部署到Tomcat的webapps目录下。前端:使用npmrunbuild打包,将生成的dist目录下的静态文件部署到Nginx服务器。以上是项目的基本设计,下面我将生成相关问题。</think>### 基于SSM+Vue的电影院购票系统设计 #### 一、项目架构设计 采用分层架构实现前后端分离: ``` 前端层 (Vue.js) ├── 用户界面组件 ├── 路由管理 (Vue Router) └── 状态管理 (Vuex) │ HTTP API (RESTful) │ 后端层 (Spring+SpringMVC+MyBatis) ├── 控制层 (Controller):处理HTTP请求 ├── 服务层 (Service):业务逻辑实现 ├── 持久层 (Mapper):数据库操作 └── 实体层 (Entity):数据模型 │ 数据库层 (MySQL) ``` #### 二、技术选型明细 | 层级 | 技术栈 | 版本 | 用途说明 | |------------|----------------------------|-----------|------------------------------| | **前端** | Vue.js | 3.x | 构建用户界面 | | | Vue Router | 4.x | 前端路由管理 | | | Vuex/Pinia | 4.x | 全局状态管理 | | | Axios | 1.x | HTTP客户端 | | | Element Plus | 2.x | UI组件库 | | **后端** | Spring Framework | 5.x | IOC容器/AOP支持 | | | Spring MVC | 5.x | Web MVC框架 | | | MyBatis | 3.5.x | ORM框架 | | | MyBatis-Spring | 2.1.x | MyBatis与Spring集成 | | **服务器** | Tomcat | 8.5 | Servlet容器 | | | Node.js | 20.x | 前端构建环境 | | **数据库** | MySQL | 5.7 | 数据存储 | | | Druid | 1.2.x | 数据库连接池 | | **工具** | Maven | 3.8+ | 后端项目管理 | | | Webpack/Vite | - | 前端构建工具 | #### 三、数据库设计(核心表) ```sql -- 1. 用户表 CREATE TABLE `user` ( `user_id` INT AUTO_INCREMENT PRIMARY KEY, `username` VARCHAR(50) UNIQUE NOT NULL, `password` VARCHAR(100) NOT NULL, -- 存储加密后密码 `email` VARCHAR(100) NOT NULL, `phone` VARCHAR(20), `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 2. 电影表 CREATE TABLE `movie` ( `movie_id` INT AUTO_INCREMENT PRIMARY KEY, `title` VARCHAR(200) NOT NULL, `director` VARCHAR(100), `actors` VARCHAR(300), `duration` INT NOT NULL, -- 分钟为单位 `release_date` DATE, `poster_url` VARCHAR(200), `description` TEXT ); -- 3. 放映厅表 CREATE TABLE `cinema_hall` ( `hall_id` INT AUTO_INCREMENT PRIMARY KEY, `hall_name` VARCHAR(50) NOT NULL, `seat_layout` VARCHAR(20) NOT NULL -- 如"10x8"表示10排8座 ); -- 4. 场次表 CREATE TABLE `schedule` ( `schedule_id` INT AUTO_INCREMENT PRIMARY KEY, `movie_id` INT NOT NULL, `hall_id` INT NOT NULL, `start_time` DATETIME NOT NULL, `price` DECIMAL(8,2) NOT NULL, FOREIGN KEY (`movie_id`) REFERENCES `movie`(`movie_id`), FOREIGN KEY (`hall_id`) REFERENCES `cinema_hall`(`hall_id`) ); -- 5. 订单表 CREATE TABLE `order` ( `order_id` VARCHAR(32) PRIMARY KEY, -- 使用UUID生成 `user_id` INT NOT NULL, `schedule_id` INT NOT NULL, `total_amount` DECIMAL(10,2) NOT NULL, `status` TINYINT NOT NULL DEFAULT 0, -- 0:待支付 1:已支付 2:已取消 `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (`user_id`) REFERENCES `user`(`user_id`), FOREIGN KEY (`schedule_id`) REFERENCES `schedule`(`schedule_id`) ); -- 6. 订单座位表 CREATE TABLE `order_seat` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `order_id` VARCHAR(32) NOT NULL, `seat_row` TINYINT NOT NULL, `seat_col` TINYINT NOT NULL, FOREIGN KEY (`order_id`) REFERENCES `order`(`order_id`) ); ``` #### 四、关键实现方案 1. **前后端交互** - 使用Axios发起RESTful请求 - 响应格式统一:`{ code: 200, data: {}, message: "" }` - 跨域解决方案:Spring MVC配置CORS ```java @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowCredentials(true); } } ``` 2. **MyBatis集成** - 数据源配置(application.properties): ```properties spring.datasource.url=jdbc:mysql://localhost:3306/cinema_db?useSSL=false spring.datasource.username=root spring.datasource.password=your_password spring.datasource.driver-class-name=com.mysql.jdbc.Driver mybatis.mapper-locations=classpath:mapper/*.xml ``` 3. **事务管理** - 购票事务示例: ```java @Service public class TicketService { @Transactional public void purchaseTickets(String orderId, List<Seat> seats) { // 1. 创建订单 orderMapper.createOrder(orderId, ...); // 2. 锁定座位 seats.forEach(seat -> seatMapper.lockSeat(seat.getScheduleId(), seat.getRow(), seat.getCol())); // 3. 生成订单明细 orderMapper.insertOrderSeats(orderId, seats); } } ``` 4. **安全控制** - JWT身份验证流程: ``` 用户登录 → 生成JWT → 前端存储Token → 后续请求携带Token → 后端验证Token → 访问资源 ``` - Spring拦截器验证: ```java public class JwtInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token = request.getHeader("Authorization"); if (!JwtUtils.verifyToken(token)) { throw new UnauthorizedException("无效凭证"); } return true; } } ``` #### 五、部署方案 1. **后端部署** ```bash # Maven打包 mvn clean package -DskipTests # 部署到Tomcat cp target/cinema.war $TOMCAT_HOME/webapps/ ``` 2. **前端部署** ```bash # 安装依赖 npm install # 生产环境构建 npm run build # 部署到Nginx cp -r dist/* /usr/share/nginx/html/ ``` 3. **Nginx配置反向代理** ```nginx server { listen 80; server_name cinema.com; location /api { proxy_pass http://localhost:8080/cinema; proxy_set_header Host $host; } location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } } ``` #### 六、性能优化建议 1. 使用Redis缓存:电影信息、热门场次数据 2. 数据库读写分离:主库处理写操作,从库处理查询 3. 支付异步处理:使用消息队列(如RocketMQ)解耦支付流程 4. CDN加速:电影海报等静态资源分发
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜗牛乌龟一起走

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值