>
快捷搜索:

附源代码,Java并发编制程序

- 编辑:皇家国际app -

附源代码,Java并发编制程序

金玉锦绣方案:

现实贯彻分为浅拷贝和深拷贝 浅拷贝(shallow copy)

被复制对象的具有变量都包涵与原本的目标一样的值(仅对于简易的值类型数据),而具有的对别的对象的援引都依旧指向原本的对象。换言之,只担当克隆按值传递的数目(譬喻:基本数据类型、String类型)。 简单来说正是只创制了栈中的指针(有个别是指针,有些直接是多少),而三个指针指向的堆中的地址是平等的。即未有创建真实的靶子,退换个中的某多个,另八个也会相应的转移,因为那就是二个指标。但多少数据类型在栈中存款和储蓄,那么浅拷贝就足以兑现。 在Java中object实现了浅拷贝。所以具备的指标间接调用super.clone()就能够。深拷贝 (deep copy)

被复制对象的兼具的变量都包含与原本的对象一样的值,除去那三个引用其余对象的变量。那么些援用别的对象的变量将本着被复制过的新指标,而不再是原来的那个被援用的目的。换言之,除了浅度克隆要克隆的值外,还背负克隆引用类型的多寡,基本上正是被克隆实例全体的属性的数据都会被克隆出来。 简言之,除了栈中的指针(有些是指针,某个直接是数量),堆中的具体指标也会被克隆一边。即货仓都是新数据。所以个别发生的修改不会潜移暗化到对方。 Java中,深度复制只需兑现CloneAble接口,完毕clone函数,具体情状具体深入分析就能够。

什么是CAS

CAS,Compare and Swap即相比较并交流。 java.util.concurrent包借助CAS完结了界别于synchronized同步锁的一种乐观锁。乐观锁正是每回去取数据的时候都乐观的以为数额不会被改换,所以不会上锁,不过在立异的时候会咬定一下在此时期数据有未有创新。CAS有3个操作数:内部存款和储蓄器值V,旧的预想值A,要修改的新值B。当且仅当预期值A和内部存款和储蓄器值V相同时,将内部存款和储蓄器值V修改为B,不然怎样都不做。CAS的关键点在于,系统在硬件层面确定保证了对比并交流操作的原子性,管理器使用基于对缓存加锁或总线加锁的方式来促成多管理器之间的原子操作。

依赖

jedis:

 <!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>

连接池:

 <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.4.2</version> </dependency>
  1. 设置JDK,本示例采纳1.7版本;
  2. 安装Tomcat;
  3. 安装MySql;
  4. 安装IEDA2017;
原型方式(Prototype Pattern)是用来成立重复的靶子,同一时间又能担保品质。那种类型的设计方式属于成立型方式,它提供了一种成立对象的最棒艺术。

原子更新基本类型类

用于通过原子的点子革新为主类型,Atomic包提供了以下八个类:

  • AtomicBoolean:原子更新布尔类型。
  • AtomicInteger:原子更新整型。
  • AtomicLong:原子更新长整型。

AtomicInteger的常用方法如下:

  • int addAndGet(int delta) :以原子格局将输入的数值与实例中的值(AtomicInteger里的value)相加,并再次来到结果
  • boolean compareAndSet(int expect, int update) :若是输入的数值等于预期值,则以原子方式将该值设置为输入的值。
  • int getAndIncrement():以原子格局将如今值加1,注意:这里重回的是自增前的值。
  • void lazySet(int newValue):最后会设置成newValue,使用lazySet设置值后,也许引致别的线程在之后的一小段时光内依然足以读到旧的值。关于该格局的越多新闻能够参见并发网翻译的一篇文章《AtomicLong.lazySet是何许做事的?》
  • int getAndSet(int newValue):以原子格局设置为newValue的值,并重临旧值。
CountDownLatch countDownLatch = new CountDownLatch;

安装

参考: wget tar -zcvf redis-4.0.8.tar.gz$ cd redis-4.0.8$ make启动src/redis-server内置的命令行工具command line interfacesrc/redis-cli

参考:

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" ><generatorConfiguration> <classPathEntry location="C:Usersxiehan.m2repositorymysqlmysql-connector-java5.1.37mysql-connector-java-5.1.37.jar"/> <context > <!-- 是否生成注释 --> <commentGenerator> <property name="suppressDate" value="true"/> <property name="suppressAllComments" value="true"/> </commentGenerator> <!-- 数据库连接 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/ssmdemo" userId="root" password="root" /> <!-- 生成的包名和工程名 --> <javaModelGenerator targetPackage="com.ssmdemo.model" targetProject="src/main/java"/> <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources" /> <javaClientGenerator targetPackage="com.ssmdemo.dao" targetProject="src/main/java" type="XMLMAPPER" /> <!-- 数据库表 --> <table tableName="UnitInfo" schema="" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false" > </table> </context></generatorConfiguration>
这种格局是兑现了多个原型接口,该接口用于创制当前指标的仿造。当直接成立对象的代价一点都相当的大时,则接纳这种格局。譬喻,叁个指标急需在三个高代价的数据库操作之后被创造。大家能够缓存该对象,在下二个呼吁时回来它的仿制,在必要的时候更新数据库,以此来缩短数据库调用。
  1. 当二个连串应该单独于它的出品创立,构成和代表时。
  2. 当要实例化的类是在运作时刻钦定期,比方,通过动态装载。
  3. 为了幸免创造八个与制品类档案的次序平行的厂子类档次时。
  4. 当二个类的实例只可以有多少个例外情况组合中的一种时。构造建设相应数指标原型并克隆它们恐怕比每便用方便的情况手工业实例化该类更有益一些。
  1. 细胞分歧。
  2. JAVA 中的 Object clone() 方法。
  1. 天性升高。
  2. 规避构造函数的自律。
  1. 布署克隆方法需求对类的功力扩充通盘思量,这对于斩新的类不是很难,但对于已某些类不料定很轻便,特别当二个类援引不协理串行化的直接对象,也许引用含有循环结构的时候。
  2. 必得兑现 Cloneable 接口。
  3. 规避构造函数的约束。
  1. 财富优化场景。
  2. 类初步化供给消化相当多的财富,这几个能源富含数据、硬件能源等。
  3. 属性和平安须求的场景。
  4. 透过 new 发生一个目的急需非凡繁琐的多寡绸缪或访谈权限,则可以运用原型方式。
  5. 四个目的七个修改者的风貌。
  6. 一个对象急需提需求任何对象访谈,何况各种调用者大概都须求修改其值时,能够设想选择原型情势拷贝多少个指标供调用者使用。
  7. 在骨子里项目中,原型情势相当少单独出现,平日是和工厂方法情势一齐出现,通过 clone 的秘籍制造一个对象,然后由工厂方法提须要调用者。原型方式已经与 Java 融为浑然一体,我们可以随手拿来利用。注意事项:与经过对二个类进行实例化来组织新对象不一致的是,原型格局是由此拷贝贰个存世对象生成新指标的。浅拷贝完成Cloneable,重写,深拷贝是通过兑现 Serializable 读取二进制流。

原子更新数组类

通过原子的艺术立异数组里的某部成分,Atomic包提供了以下多个类:

  • AtomicIntegerArray:原子更新整型数组里的因素。

  • AtomicLongArray:原子更新长整型数组里的因素。

  • AtomicReferenceArray:原子更新引用类型数组里的因素。

  • AtomicIntegerArray类重尽管提供原子的格局立异数组里的整型,其常用艺术如下

  • int addAndGet(int i, int delta):以原子格局将输入值与数组中索引i的成分相加。

  • boolean compareAndSet(int i, int expect, int update):要是当前值等于预期值,则以原子格局将数组地方i的要素设置成update值。

示例:

public class AtomicIntegerArrayTest { static int[] value = new int[]{1,2}; static AtomicIntegerArray ai = new AtomicIntegerArray; public static void main(String[] args) { ai.getAndSet; System.out.println); }}
  • 暗中同意非公平
  • 构造方法参数即许可数,被设置到了AbstractQueuedSynchronizer的state属性
  • 线程先品尝获得认同,假使成功,许可数-1;线程运营结束后放走许可,许可数+1
  • 许可数为0,则收获战败;线程踏向AQS的一块队列,被别的释放许可的线程唤醒

jedis操作redis

package impl.service.redis;import face.service.RedisService;import org.junit.Before;import org.junit.Test;import redis.clients.jedis.Jedis;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;/** * @author futao * Created on 18-2-28-下午5:15. */public class RedisServiceImpl implements RedisService { private Jedis jedis; @Before public void setup() { /*连接redis服务器*/ jedis = new Jedis("127.0.0.1", 6379); /*权限,密码*/ //jedis.auth; } /** * jedis存储字符串 */ @Test public void testString() { /*向redis中存String键值对 set*/ jedis.set("name", "futao"); /*从redis中读取String get*/ System.out.println(jedis.get; /*拼接*/ jedis.append("name", " is 666"); System.out.println(jedis.get; /*删除某个键值对*/ jedis.del; System.out.println("del===" + jedis.get; /*一次性添加多个键值对*/ jedis.mset("k1", "v1", "k2", "v2", "age", "16"); System.out.println(jedis.get; System.out.println(jedis.get; System.out.println(jedis.get; /*age加一*/ jedis.incr; System.out.println(jedis.get; /*String类型的数据设置过期时间*/ jedis.setex("name", 5, "Nicai"); System.out.println(jedis.get; } /** * jedis操作map */ @Test public void testMap() { Map<String, String> map = new HashMap<>(); map.put("user", "futao"); map.put("age", "18"); map.put("sex", "男"); /*存hashMap数据,hmset()*/ jedis.hmset("futaoInfo", map); /*设置过期时间*/ jedis.expire("futaoInfo", 5); /*读取hashMap数据结构的数据。返回的是一个List*/ System.out.println(jedis.hmget("futaoInfo", "sex", "user")); List<String> list = jedis.hmget("futaoInfo", "sex", "sex", "age"); list.forEach(System.out::println); /*删除map中的某个键值对*/ jedis.hdel("futaoInfo", "age"); /*返回key为futaoInfo的键中存放的值的个数*/ System.out.println("hlen===" + jedis.hlen("futaoInfo")); /*是否存在该key*/ System.out.println("exist===" + jedis.exists("futaoInfo")); /*返回map对象中的所有key */ System.out.println("map-all-keys" + jedis.hkeys("futaoInfo")); /*返回map对象中的所有value */ System.out.println("map-all-value" + jedis.hvals("futaoInfo")); Iterator<String> iterator = jedis.hkeys("futaoInfo").iterator(); /*遍历map中存储的key-value*/ while (iterator.hasNext { String key = iterator.next(); System.out.println(key + "::" + jedis.hget("futaoInfo", key)); } for (String key : jedis.hkeys("futaoInfo")) { System.out.println(key + "::" + jedis.hget("futaoInfo", key)); } } /** * jedis操作list */ @Test public void testList() { /*添加list数据*/ jedis.lpush("javaFramework", "Spring", "SpringMVC", "Hibernate"); /*获取list中的数据.-1表示获取所有数据*/ List<String> javaFramework = jedis.lrange("javaFramework", 0, -1); for (String a : javaFramework) { System.out.println; } } /** * jedis操作set * ********************** * * jedis支持有序set集合 * * ********************** */ @Test public void testSet() { /*存*/ jedis.sadd("username", "futao"); jedis.sadd("username", "futao1"); jedis.sadd("username", "futao2"); jedis.sadd("username", "futao3", "futao4", "futao5"); /*读取set的所有value*/ System.out.println(jedis.smembers("username")); /*判断futao是否是username的value*/ System.out.println(jedis.sismember("username", "futao")); /*从key为username的set中随机读取一个值*/ System.out.println(jedis.srandmember("username")); /*返回集合元素的个数*/ System.out.println(jedis.scard("username")); } @Test public void test() { jedis.del; jedis.rpush; jedis.lpush("b", "-5"); jedis.lpush; jedis.lpush("b", "99"); jedis.lpush("b", "-666"); System.out.print("before sort" + jedis.lrange("b", 0, -1)); List<String> b = jedis.sort; System.out.println; /*并不会改变原来的数据*/ System.out.print("nafter sort" + jedis.lrange("b", 0, -1)); }}

图片 1新建.png图片 2初始配置.png图片 3选择maven路径.png图片 4新建筑工程程.png

情势组织

  1. 简言之原型方式:用于原型的版本异常少的时候

    图片 5简易原型形式

  2. 挂号格局的原型情势:假如原型的兑现比相当多样本子,那么通过三个挂号处理类,能够低价的落到实处原型的治本。

    图片 6注册情势的原型形式

/** * @see 直接继承Java的Cloneable即可 * @author Thornhill * */public interface Splittable extends Cloneable { public Splittable clone() throws CloneNotSupportedException; public void showSelf();}

假设有更加多的职能,能够加在此接口中

import prototype.Splittable;/** * @see 肌肉细胞 * @author Thornhill * */public class MuscleCells implements Splittable { private String cellType = "肌肉细胞"; private String cellName; private String cellLocation; public MuscleCells(String cellName, String cellLocation) { this.cellName = cellName; this.cellLocation = cellLocation; } public Splittable clone() { return new MuscleCells(cellName, cellLocation); } public String getCellName() { return cellName; } public void setCellName(String cellName) { this.cellName = cellName; } public String getCellLocation() { return cellLocation; } public void setCellLocation(String cellLocation) { this.cellLocation = cellLocation; } @Override public void showSelf() { System.out.println(cellType + " " + cellName + " " + cellLocation); }}

其实处境是极度复杂的,原型格局正是为了消除重复创制的赫赫成本和冗余代码。

import prototype.Splittable;public class CellsManager { private static Map<String, Splittable> map = new HashMap<String, Splittable>(); private CellsManager() { }; public static Splittable getCells(String cellType) { Splittable cell = map.get; return cell; } public static void putCells(String cellType, Splittable cell) { map.put(cellType, cell); } public static void removeCells(String cellType) { map.remove; }}

纯静态类,具体职能为原型的治本。

import concretePrototype.MuscleCells;import prototype.Splittable;import prototypeManager.CellsManager;public class Client { public static void main(String[] args) throws CloneNotSupportedException { /** * 创建一个肌肉细胞,放到原型管理中 */ Splittable cell = new MuscleCells("肌肉甲", "肱二头肌"); CellsManager.putCells("肌肉细胞", cell); cell.showSelf(); /** * 现在还需要一个肌肉细胞肌肉乙,除了名字,其他都一样,我们就使用克隆 */ MuscleCells cell1 = (MuscleCells) CellsManager.getCells.clone(); cell1.setCellName; cell1.showSelf(); }}

肌肉细胞 肌肉甲 肱二头肌肌肉细胞 肌肉乙 肱二头肌

附源代码,Java并发编制程序。原型格局适用于必要一再次创下造对象,而新目的和旧指标相似度极高或创造对象费用十分的大时利用。切合开闭原则,平常无需修改抽象原型和原型处理器,只须要参与新的子类就能够。 GitHub源代码

吃完饭之后甜品

Atomic包提供了三种基本类型的原子更新,可是Java的主导项目里还会有char,float和double等。那么难点来了,如何原子的更新任何的核心项目呢?Atomic包里的类基本都是行使Unsafe达成的,让大家一同看下Unsafe的源码,发掘Unsafe只提供了三种CAS方法,compareAndSwapObject,compareAndSwapInt和compareAndSwapLong,再看AtomicBoolean源码,开掘其是先把Boolean调换到整型,再利用compareAndSwapInt实行CAS,所以原子更新double也足以用类似的思路来贯彻。

  • 将AQS中的state值+1
  • 通过doReleaseShared()唤醒同步队列中的第贰个节点

redis连接池

package impl.service.redis;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;/** * @author futao * Created on 18-2-28-下午7:13. */public class RedisUtil { /*服务器地址*/ private static final String HOST = "127.0.0.1"; /*端口*/ private static final int PORT = 6379; /*权限密码*/ private static final String PASSWORD = null; //可用连接实例的最大数目,默认值为8; //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted。 private static final int MAX_TOTAL = 1024; //控制一个pool最多有多少个状态为idle的jedis实例,默认值也是8。 private static final int MAX_IDLE = 200; //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException; private static final int MAX_WAIT = 10000; private static final int TIMEOUT = 10000; //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的; private static final boolean TEST_ON_BORROW = true; private static JedisPool jedisPool = null; static { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(MAX_TOTAL); jedisPoolConfig.setMaxIdle; jedisPoolConfig.setMaxWaitMillis; jedisPoolConfig.setTestOnBorrow(TEST_ON_BORROW); jedisPool = new JedisPool(jedisPoolConfig, HOST, PORT, TIMEOUT, PASSWORD); } /** * 获取jedis * * @return jedis实例 */ public synchronized static Jedis getJedis() { if (jedisPool != null) { Jedis resource = jedisPool.getResource(); return resource; } else { return null; } } /** * 释放jedis资源 * * @param jedis */ public static void releaseResource(final Jedis jedis) { if (jedis != null) { jedisPool.returnResource; } }}

 @Test public void testRedisPool() { Jedis jedis = RedisUtil.getJedis(); jedis.del; jedis.lpush("a", "111", "222", "333"); List<String> a = jedis.lrange("a", 0, -1); for (String i : a) { System.out.println; } /*记得要释放资源*/ RedisUtil.releaseResource; }

spring-mybatis.xml

Atomic包介绍

合法解释:八个Mini工具包,支持单变量上的无锁线程安全编制程序。

图片 7image.png

能够看出,它个中有16个java类。

public CyclicBarrier(int parties) { this(parties, null);}// parties:栅栏放开前需要调用的线程数// count:当前剩余需要调用的线程数// barrierCommand:调用线程数满足后,栅栏放开前执行的命令public CyclicBarrier(int parties, Runnable barrierAction) { if (parties <= 0) throw new IllegalArgumentException(); this.parties = parties; this.count = parties; this.barrierCommand = barrierAction;}// 用法,每个线程调用await,耗完parties即可往下走CyclicBarrier.await final ReentrantLock lock = this.lock; // this就是CyclicBarrier lock.lock(); // 先拿锁 int index = --count; if (index == 0) { // 判断index,为0表示线程数已达到 boolean ranAction = false; try { final Runnable command = barrierCommand; if (command != null) // 可能是空的,看构造函数了 command.run(); ranAction = true; nextGeneration(); // signalAll,重置count,重置generation return 0; // await结束 } finally { if (!ranAction) // command.run异常时,打破栅栏,释放线程 breakBarrier(); // signalAll,重置count,设置broken属性 } } trip.await // 自我阻塞private void nextGeneration() { // signal completion of last generation trip.signalAll(); // trip:lock生成的Condition // set up next generation count = parties; generation = new Generation();}private void breakBarrier() { generation.broken = true; count = parties; trip.signalAll();}

/** * Makes available the permit for the given thread, if it * was not already available. If the thread was blocked on * {@code park} then it will unblock. Otherwise, its next call * to {@code park} is guaranteed not to block. This operation * is not guaranteed to have any effect at all if the given * thread has not been started. * * @param thread the thread to unpark, or {@code null}, in which case * this operation has no effect*/ public static void unpark(Thread thread) { if (thread != null) UNSAFE.unpark; }// 从上面注释可以看出,unpack可以释放park状态线程,或者将执行park的线程;不过对于还没开始执行的线程,unpark并不保证效果/** * Disables the current thread for thread scheduling purposes unless the * permit is available. * * <p>If the permit is available then it is consumed and the call * returns immediately; otherwise the current thread becomes disabled * for thread scheduling purposes and lies dormant until one of three * things happens: * * <ul> * * <li>Some other thread invokes {@link #unpark unpark} with the * current thread as the target; or * * <li>Some other thread {@linkplain Thread#interrupt interrupts} * the current thread; or * * <li>The call spuriously (that is, for no reason) returns. * </ul> * * <p>This method does <em>not</em> report which of these caused the * method to return. Callers should re-check the conditions which caused * the thread to park in the first place. Callers may also determine, * for example, the interrupt status of the thread upon return.*/ public static void park() { UNSAFE.park(false, 0L); }

此间的目录建好之后还索要安装一下,让idea识别目录效用,采用File-Project Structure

原子更新援用类型

原子更新为主类型的AtomicInteger,只能更新贰个变量,假如要原子的更新五个变量,就要求选拔那一个原子更新引用类型提供的类。Atomic包提供了以下多个类:

AtomicReference:原子更新援用类型。AtomicReferenceFieldUpdater:原子更新援引类型里的字段。Atomic马克ableReference:原子更新带有标志位的征引类型。能够原子的翻新一个布尔类型的标志位和引用类型。构造方法是Atomic马克ableReference(V initialRef, boolean initial马克)

AtomicReference的行使例子代码如下:

package com.thread.atomic;import java.util.concurrent.atomic.AtomicReference;/** * Created by Fant.J. * 2018/2/28 18:40 */public class AtomicReferenceTest { static AtomicReference<User> ar = new AtomicReference<>(); public static void main(String[] args) { User user = new User("fantj",20); User updateUser = new User("dalao",20); ar.set; ar.compareAndSet(user,updateUser); //public final boolean compareAndSet(User expect, User update) System.out.println.getName() + " :"+ar.get().getAge; } static class User{ private String name; private Integer age; public User(String name, int i) { this.name = name; this.age=i; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }}
  • 对象锁
    • 相似指synchronized,和对象有关
    • 各类对象都有个藏匿的监视器,用于线程的一路
    • 线程状态:创造->就绪->运营->阻塞(lock/wait/join/sleep)->销毁
  • ReentrantLock
    • 互斥锁
    • 可重入
  • Condition
    • 实现wait,notify,notifyAll的功能
  • ReadWriteLock - ReentrantReadWriteLock
    • 分享锁:读读共享
<?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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 扫描service包下所有使用注解的类型 --> <context:component-scan base-package="com.ssmdemo.service"/> <!-- 配置数据库相关参数properties的属性:${url} --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 数据库连接池 --> <bean > <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="maxPoolSize" value="${c3p0.maxPoolSize}"/> <property name="minPoolSize" value="${c3p0.minPoolSize}"/> <property name="autoCommitOnClose" value="${c3p0.autoCommitOnClose}"/> <property name="checkoutTimeout" value="${c3p0.checkoutTimeout}"/> <property name="acquireRetryAttempts" value="${c3p0.acquireRetryAttempts}"/> </bean> <!-- 配置SqlSessionFactory对象 --> <bean > <!-- 注入数据库连接池 --> <property name="dataSource" ref="dataSource"/> <!-- 扫描model包 使用别名 --> <property name="typeAliasesPackage" value="com.ssmdemo.model"/> <!-- 扫描sql配置文件:mapper需要的xml文件 --> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <!-- 配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中 --> <bean > <!-- 注入sqlSessionFactory --> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!-- 给出需要扫描Dao接口包 --> <property name="basePackage" value="com.ssmdemo.dao"/> </bean> <!-- 配置事务管理器 --> <bean > <!-- 注入数据库连接池 --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置基于注解的声明式事务 --> <tx:annotation-driven transaction-manager="transactionManager"/></beans>

本文由皇家国际app发布,转载请注明来源:附源代码,Java并发编制程序