@Service用于标注业务层组件
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件.
@Component泛指组件
@Autowired:它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。
在@Qualifier这个注解中我们申明其引用的是哪一个bean,spring便会自动为其注入这个实例.
@Autowired
@Qualifier("mySessionFactory")
private SessionFactory sf;
注解 @Scope("prototype") 相当于applicationContext.xml文件中bean节点中scope属性,这个非单例模式注解十分重要,主要起到线程安全,防止并发操作时出现异常的作用.
spring中bean属性scope介绍
singleton:SpringIoc容器只会创建该Bean的唯一实例,所有的请求和引用都只使用这个实例
Property: 每次请求都创建一个实例
request: 在一次Http请求中,容器会返回该Bean的同一个实例,而对于不同的用户请求,会返回不同的实例。需要注意的是,该作用域仅在基于Web的Spring ApplicationContext情形下有效,以下的session和global Session也是如此
session:同上,唯一的区别是请求的作用域变为了session
global session:全局的HttpSession中,容器会返回该bean的同一个实例,典型为在是使用portlet context的时候有效
单独使用BEAN:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-cfg.xml");
StockInfoDao stockInfoDao = applicationContext.getBean(StockInfoDao.class);
JAVAFX Controller:
ApplicationContext applicationContext = ..
FXMLLoader loader = new FXMLLoader();
loader.setControllerFactory(applicationContext::getBean);
loader.setLocation(Object.class.getResource(UiBaseService.getInstance().getMainFxmlFullPath()));
Scene scene = new Scene(loader.load());
事务:
@Service
public class SelfSelectedStockServiceImpl implements SelfSelectedStockService{
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
public boolean delSelfSelectedStock(long selfSelectedStockId) {...}
}
Spring事务管理中@Transactional的propagation参数(事务传播行为)
REQUIRED的含义是,支持当前已经存在的事务,如果还没有事务,就创建一个新事务。
MANDATORY的含义是,支持当前已经存在的事务,如果还没有事务,就抛出一个异常。
NESTED的含义是,在当前事务中创建一个嵌套事务,如果还没有事务,那么就简单地创建一个新事务。
REQUIRES_NEW的含义是,挂起当前事务,创建一个新事务,如果还没有事务,就简单地创建一个新事务。
NOT_SUPPORTED的含义是,强制不在事务中运行,如果当前存在一个事务,则挂起该事务。
SUPPORTS的含义是,支持当前事务,如果没有事务那么就不在事务中运行。SUPPORTS传播性的逻辑含义比较模糊,因此一般是不推荐使用的。
Spring事务管理中@Transactional的isolation参数(事务隔离级别)
Isolation.DEFAULT:为数据源的默认隔离级别
isolation=Isolation.READ_UNCOMMITTED:未授权读取级别
以操作同一行数据为前提,读事务允许其他读事务和写事务,未提交的写事务禁止其他写事务(但允许其他读事务)。此隔离级别可以防止更新丢失,但不能防止脏读、不可重复读、幻读。此隔离级别可以通过“排他写锁”实现。
iIsolation.READ_COMMITTED:授权读取级别
以操作同一行数据为前提,读事务允许其他读事务和写事务,未提交的写事务禁止其他读事务和写事务。此隔离级别可以防止更新丢失、脏读,但不能防止不可重复读、幻读。此隔离级别可以通过“瞬间共享读锁”和“排他写锁”实现。
iIsolation.REPEATABLE_READ:可重复读取级别
以操作同一行数据为前提,读事务禁止其他写事务(但允许其他读事务),未提交的写事务禁止其他读事务和写事务。此隔离级别可以防止更新丢失、脏读、不可重复读,但不能防止幻读。此隔离级别可以通过“共享读锁”和“排他写锁”实现。
iIsolation.SERIALIZABLE:序列化级别
提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。此隔离级别可以防止更新丢失、脏读、不可重复读、幻读。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。
总结:隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免更新丢失、脏读,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
Mybatis:
<?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="...SelfSelectedStockDao">
<select id="getSelfSelectedStock" parameterType="long" resultType="selfSelectedStock">
select ... from ... where id = #{id}
</select>
<delete id="deleteSelfSelectedStock" parameterType="long">
delete from ... where id=#{id}
</delete>
<insert id="insertSelfSelectedStock" useGeneratedKeys="true" keyProperty="id" >
insert into ...(...)
values(#{id},...)
</insert>
<update id="updateSelfSelectedStock" >
update ... set .. = #{..},... where id = #{id}
</update>
<select id="searchSelfSelectedStock" resultType="selfSelectedStock" >
select ... from ... where 1=1
<if test="beginDate != null"> and ... <![CDATA[ >= ]]> #{beginDate}</if>
<if test="endDate != null"> and ... <![CDATA[ <= ]]> #{endDate}</if>
<if test="stockInfoList!=null">
<foreach collection="stockInfoList" item="stockInfo">
and (stockCode like concat('%',#{stockInfo},'%') or stockName like concat('%',#{stockInfo},'%') )
</foreach>
</if>
order by ${sortColName} ${sortType} limit #{beginIndex},#{dataSize}
</select>
</mapper>
@Repository
public interface SelfSelectedStockDao {
public SelfSelectedStock getSelfSelectedStock(@Param("id") Long id);
public int insertSelfSelectedStock(SelfSelectedStock selfSelectedStock);
public int deleteSelfSelectedStock(@Param("id") Long id);
public int updateSelfSelectedStock(SelfSelectedStock selfSelectedStock);
public List<SelfSelectedStock> searchSelfSelectedStock(@Param("beginDate") Date beginDate,@Param("endDate") Date endDate,@Param("stockInfoList") List<String> stockInfoList,
@Param("beginIndex") Integer beginIndex,@Param("dataSize") Integer dataSize,@Param("sortColName") String sortColName,@Param("sortType") String sortType);
}
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>
<settings>
<!-- 这个配置使全局的映射器启用或禁用缓存 -->
<setting name="cacheEnabled" value="true" />
<!-- 允许 JDBC 支持生成的键。需要适合[修改为:适当]的驱动。如果设置为true,则这个设置强制生成的键被使用,尽管一些驱动拒绝兼容但仍然有效(比如 Derby) -->
<setting name="useGeneratedKeys" value="true" />
<!-- 配置默认的执行器。SIMPLE 执行器没有什么特别之处。REUSE 执行器重用预处理语句。BATCH 执行器重用语句和批量更新 -->
<setting name="defaultExecutorType" value="REUSE" />
<!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 设置超时时间,它决定驱动等待一个数据库响应的时间 -->
<setting name="defaultStatementTimeout" value="25000"/>
</settings>
<!-- 别名配置 -->
<typeAliases>
<typeAlias alias="selfSelectedStock" type="....pojo.SelfSelectedStock" />
...
</typeAliases>
<!-- 指定映射器路径 -->
<mappers>
<mapper resource="mybatis/mapper/SelfSelectedStockMapper.xml"/>
...
</mappers>
</configuration>
spring-cfg.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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--启用扫描机制,并指定扫描对应的包-->
<context:annotation-config />
<context:component-scan base-package="abin.stockapp.*" />
<!-- 外部属性文件 -->
<bean id="myConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<array>
<value>classpath:config/mysql.properties</value>
<value>classpath:config/redis.properties</value>
</array>
</property>
<property name="fileEncoding" value="UTF-8"></property>
</bean>
<!-- 数据库连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${mysql.driverClassName}" />
<property name="url" value="${mysql.url}" />
<property name="username" value="${mysql.username}" />
<property name="password" value="${mysql.password}" />
<!-- 初始连接池连接个数 -->
<property name="initialSize" value="5" />
<!-- 最小的空闲链接数量 -->
<property name="minIdle" value="5" />
<!-- 最大的空闲连接数量 -->
<property name="maxIdle" value="10" />
<!-- 最大活动连接数 -->
<property name="maxTotal" value="20" />
<!-- 获得连接的最大等待毫秒数 -->
<property name="maxWaitMillis" value="10000"/>
</bean>
<!-- 集成MyBatis -->
<bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--指定MyBatis配置文件-->
<property name="configLocation" value="classpath:/mybatis/mybatis-config.xml" />
</bean>
<!-- 事务管理器配置数据源事务 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 使用注解定义事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- 采用自动扫描方式创建mapper bean -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="abin.stockapp" />
<property name="sqlSessionFactoryBeanName" value="SqlSessionFactory"/>
<!-- <property name="SqlSessionFactory" ref="SqlSessionFactory" /> -->
<property name="annotationClass" value="org.springframework.stereotype.Repository" />
</bean>
<!-- redis -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!--最大空闲数 -->
<property name="maxIdle" value="50" />
<!--最大连接数 -->
<property name="maxTotal" value="100" />
<!--最大等待时间 -->
<property name="maxWaitMillis" value="20000" />
</bean>
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<property name="password" value="${redis.password}"/>
<property name="poolConfig" ref="poolConfig" />
</bean>
<bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="keySerializer" ref="stringRedisSerializer" />
<property name="valueSerializer" ref="jdkSerializationRedisSerializer" />
</bean>
</beans>
mysql.properties:
mysql.driverClassName=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/stockapp?useUnicode=true&characterEncoding=UTF-8
mysql.username=root
mysql.password=123
redis.properties:
redis.password=123
redis.host=localhost
redis.port=6379
log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 设置log4j2的自身log级别为warn -->
<!-- OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<configuration status="WARN" monitorInterval="30">
<appenders>
<console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
</console>
<!-- ${sys:user.home}/ -->
<RollingFile name="RollingFileInfo" fileName="logs/info.log" filePattern="logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<Filters>
<ThresholdFilter level="INFO"/>
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
</RollingFile>
<RollingFile name="RollingFileWarn" fileName="logs/warn.log" filePattern="logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
<Filters>
<ThresholdFilter level="WARN"/>
<ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
</RollingFile>
<RollingFile name="RollingFileError" fileName="logs/error.log" filePattern="logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
<ThresholdFilter level="ERROR"/>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
</RollingFile>
</appenders>
<loggers>
<!--过滤掉spring和hibernate的一些无用的debug信息-->
<logger name="org.springframework" level="INFO"></logger>
<logger name="org.hibernate" level="INFO"></logger>
<root level="all">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
</root>
</loggers>
</configuration>