http://www.byteslounge.com/tutorials/spring-jta-multiple-resource-transactions-in-tomcat-with-atomikos-example

Spring JTA multiple resource transactions in Tomcat with Atomikos example

17 June 2013
In this tutorial you will learn how to configure a JTA transaction manager outside an enterprise container - using the Spring framework and Atomikos, both deployed in Tomcat - in order to implement distributed multiple resource (or XA) transactions.

Introduction

Distributed multiple resource transactions in Java are usually accomplished by resorting to the Java Transaction API (JTA). One usually delegates the task of distributed transaction coordination to an entity called the Transaction Manager.

The transaction manager is then responsible for coordinating the distributed transaction by interacting with each resource's own Resource Manager. Fully fledged enterprise containers include a JTA implementation but what if we need JTA outside an enterprise container, ie. a servlet container like Tomcat?

In this case we must use a 3rd party JTA implementation. In this tutorial we will use Atomikos, a quality JTA implementation which is also available as an open source distribution, along with the Spring framework in order to implement JTA transactions.

This tutorial considers the following environment:

  1. Ubuntu 12.04
  2. JDK 1.7.0.21
  3. Spring 3.2.3
  4. Atomikos 3.8.0
  5. Tomcat 7.0.35

The following Maven dependencies are required:

Required Maven dependencies
<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <spring.version>3.2.3.RELEASE</spring.version>
  <hibernate.version>4.1.9.Final</hibernate.version>
  <atomikos.version>3.8.0</atomikos.version>
</properties>

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>${hibernate.version}</version>
    <exclusions>
      <exclusion>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
      </exclusion>
      <exclusion>
        <groupId>dom4j</groupId>
        <artifactId>dom4j</artifactId>
      </exclusion>
    </exclusions>
  </dependency>

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

  <dependency>
    <groupId>com.atomikos</groupId>
    <artifactId>transactions-jta</artifactId>
    <version>${atomikos.version}</version>
  </dependency>

  <dependency>
    <groupId>com.atomikos</groupId>
    <artifactId>transactions-jdbc</artifactId>
    <version>${atomikos.version}</version>
  </dependency>

  <dependency>
    <groupId>com.atomikos</groupId>
    <artifactId>transactions-hibernate3</artifactId>
    <version>${atomikos.version}</version>
    <exclusions>
      <exclusion>
        <artifactId>hibernate</artifactId>
        <groupId>org.hibernate</groupId>
      </exclusion>
    </exclusions>
  </dependency>

  <dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>1.6.1</version>
  </dependency>

  <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.16</version>
  </dependency>

  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.25</version>
  </dependency>

</dependencies>

Datasources

In this tutorial we will use two datasources each one of them referencing a distinct MySQL database. We could have also included a JMS message queue to participate in the distributed transaction as this is also a very common scenario, but for simplicity we will keep up with the two MySQL datasources:

The datasources used in this example
Datasource 1
Database: DATABASE1
Username: user1
Database: passwd1

Datasource 2
Database: DATABASE2
Username: user2
Database: passwd2

We will use a couple of tables in this example. Datasource 1 will contain TABLE_ONE and Datasource 2 will contain TABLE_TWO:

Tables used in this example:
Datasource 1
CREATE TABLE TABLE_ONE (
TABLE_ONE_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
VALUE VARCHAR(32) NOT NULL
);

Datasource 2
CREATE TABLE TABLE_TWO (
TABLE_TWO_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
VALUE VARCHAR(32) NOT NULL
);

JPA entities

Now we define a couple of JPA entities to map the two tables mentioned in the previous section.

TableOne.java
package com.byteslounge.spring.tx.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "TABLE_ONE")
public class TableOne {

  @Id
    @Column(name = "TABLE_ONE_ID", nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
  private int tableOneId;

  @Column(name = "VALUE", nullable = false)
  private String value;

  public int getTableOneId() {
    return tableOneId;
  }

  public void setTableOneId(int tableOneId) {
    this.tableOneId = tableOneId;
  }

  public String getValue() {
    return value;
  }

  public void setValue(String value) {
    this.value = value;
  }

}
TableTwo.java
package com.byteslounge.spring.tx.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "TABLE_TWO")
public class TableTwo {

  @Id
    @Column(name = "TABLE_TWO_ID", nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
  private int tableTwoId;

  @Column(name = "VALUE", nullable = false)
  private String value;

  public int getTableTwoId() {
    return tableTwoId;
  }

  public void setTableTwoId(int tableTwoId) {
    this.tableTwoId = tableTwoId;
  }

  public String getValue() {
    return value;
  }

  public void setValue(String value) {
    this.value = value;
  }

}

DAO definition

We will also use a couple of Spring services as DAO's where each one is used to interact with the respective datasource. Following next are the DAO's interfaces and implementations:

TableOneDao.java
package com.byteslounge.spring.tx.dao;

import com.byteslounge.spring.tx.entity.TableOne;

public interface TableOneDao {

  void save(TableOne tableOne);

}
TableOneDaoImpl.java
package com.byteslounge.spring.tx.dao.impl;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Service;

import com.byteslounge.spring.tx.dao.TableOneDao;
import com.byteslounge.spring.tx.entity.TableOne;

@Service
public class TableOneDaoImpl implements TableOneDao {

  private EntityManager entityManager;

  @PersistenceContext(unitName="PersistenceUnit1")
  public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
  }

  @Override
  public void save(TableOne tableOne) {
    entityManager.persist(tableOne);
  }

}
TableTwoDao.java
package com.byteslounge.spring.tx.dao;

import com.byteslounge.spring.tx.entity.TableTwo;

public interface TableTwoDao {

  void save(TableTwo tableTwo) throws Exception;

}
TableTwoDaoImpl.java
package com.byteslounge.spring.tx.dao.impl;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Service;

import com.byteslounge.spring.tx.dao.TableTwoDao;
import com.byteslounge.spring.tx.entity.TableTwo;

@Service
public class TableTwoDaoImpl implements TableTwoDao {

  private EntityManager entityManager;

  @PersistenceContext(unitName="PersistenceUnit2")
  public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
  }

  @Override
  public void save(TableTwo tableTwo) throws Exception {
    entityManager.persist(tableTwo);
    throw new Exception("Force transaction rollback");
  }

}

There are a couple of things to note in this DAO's. The first one is that each DAO is associated with a distinct PersistenceUnit(we will see how to configure them later in this tutorial).

The second one is that the save method of TableTwoDaoImpl is explicitly throwing an exception. This exception will be used to force the global transaction to rollback. We will also see this in detail in the following tutorial sections.

The transaction service

Finally we need a service to implement our global container managed transaction. Following next is a possible service interface and implementation:

TransactionalService.java
package com.byteslounge.spring.tx.service;

import com.byteslounge.spring.tx.entity.TableOne;
import com.byteslounge.spring.tx.entity.TableTwo;

public interface TransactionalService {

  void persist(TableOne tableOne, TableTwo tableTwo) throws Exception;

}
TransactionalServiceImpl.java
package com.byteslounge.spring.tx.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.byteslounge.spring.tx.dao.TableOneDao;
import com.byteslounge.spring.tx.dao.TableTwoDao;
import com.byteslounge.spring.tx.entity.TableOne;
import com.byteslounge.spring.tx.entity.TableTwo;
import com.byteslounge.spring.tx.service.TransactionalService;

@Service
public class TransactionalServiceImpl
         implements TransactionalService {

  @Autowired
  private TableOneDao tableOneDao;

  @Autowired
  private TableTwoDao tableTwoDao;

  @Override
  @Transactional(rollbackFor=Exception.class)
  public void persist(TableOne tableOne, TableTwo tableTwo)
         throws Exception {

    tableOneDao.save(tableOne);
    tableTwoDao.save(tableTwo);

  }

}

Thing to note in this service implementation: Method persist is annotated with @Transactional so the method will be executed in a transactional fashion by the Spring container. This method will call the data persistence methods for both DAO's we defined earlier.

Transactional annotation has the rollbackFor attribute defined with Exception.class value. This means that the transaction will rollback if an exception of type Exception occurs inside persist method execution.

You can refine the exception types that cause a transaction rollback but for the simplicity of this example we will keep with Exception.

Persistence Context configuration

Now the Persistence Context configuration (persistence.xml):

persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
  xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
  http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

 <persistence-unit name="PersistenceUnit1" transaction-type="JTA">
  <class>com.byteslounge.spring.tx.entity.TableOne</class>
  <properties>
   <property name="hibernate.transaction.manager_lookup_class"
   value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup" />
   <property name="hibernate.transaction.factory_class"
   value="org.hibernate.transaction.CMTTransactionFactory" />
  </properties>
 </persistence-unit>

 <persistence-unit name="PersistenceUnit2" transaction-type="JTA">
  <class>com.byteslounge.spring.tx.entity.TableTwo</class>
  <properties>
   <property name="hibernate.transaction.manager_lookup_class"
   value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup" />
   <property name="hibernate.transaction.factory_class"
   value="org.hibernate.transaction.CMTTransactionFactory" />
  </properties>
 </persistence-unit>

</persistence>

Here we configure the Persistence Units we are injecting in the DAO's we defined earlier. Note that transaction-type attribute of each persistence unit is defined as JTA.

We also define where Hibernate should look for a Transaction Manager. Since we are using Atomikos we will define it as the Hibernate TransactionManagerLookup provided by Atomikos (we are using Hibernate as JPA implementation).

Spring configuration

Now we define the necessary Spring beans and also the Spring container configuration:

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:p="http://www.springframework.org/schema/p"
  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-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">

  <tx:annotation-driven />
  <tx:jta-transaction-manager />

  <context:component-scan
    base-package="com.byteslounge.spring.tx.dao.impl" />
  <context:component-scan
    base-package="com.byteslounge.spring.tx.service.impl" />
  <context:component-scan
    base-package="com.byteslounge.spring.tx.servlet" />

  <bean id="entityManagerFactory1"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="PersistenceUnit1" />
    <property name="dataSource" ref="dataSource1" />
    <property name="jpaVendorAdapter">
      <bean
      class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="showSql" value="true" />
        <property name="databasePlatform"
            value="org.hibernate.dialect.MySQL5InnoDBDialect" />
      </bean>
    </property>
  </bean>

  <bean id="entityManagerFactory2"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="PersistenceUnit2" />
    <property name="dataSource" ref="dataSource2" />
    <property name="jpaVendorAdapter">
      <bean
      class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="showSql" value="true" />
        <property name="databasePlatform"
            value="org.hibernate.dialect.MySQL5InnoDBDialect" />
      </bean>
    </property>
  </bean>

  <bean id="dataSource1"
    class="com.atomikos.jdbc.AtomikosDataSourceBean"
    init-method="init" destroy-method="close">

    <property name="uniqueResourceName" value="DataSource1" />
    <property name="xaDataSource" ref="dataBase1" />
    <property name="poolSize" value="3" />

  </bean>

  <bean id="dataBase1"
    class="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"
    lazy-init="true">

    <property name="pinGlobalTxToPhysicalConnection" value="true" />
    <property name="user" value="user1" />
    <property name="password" value="passwd1" />
    <property name="url" value="jdbc:mysql://localhost:3306/DATABASE1" />

  </bean>

  <bean id="dataSource2"
    class="com.atomikos.jdbc.AtomikosDataSourceBean"

    init-method="init" destroy-method="close">
    <property name="uniqueResourceName" value="DataSource2" />
    <property name="xaDataSource" ref="dataBase2" />
    <property name="poolSize" value="3" />

  </bean>

  <bean id="dataBase2"
    class="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"

    lazy-init="true">
    <property name="pinGlobalTxToPhysicalConnection" value="true" />
    <property name="user" value="user2" />
    <property name="password" value="passwd2" />
    <property name="url" value="jdbc:mysql://localhost:3306/DATABASE2" />

  </bean>

  <bean id="atomikosTransactionManager"
    class="com.atomikos.icatch.jta.UserTransactionManager"
    init-method="init" destroy-method="close">

    <property name="forceShutdown" value="false" />

  </bean>

  <bean id="atomikosUserTransaction"
    class="com.atomikos.icatch.jta.J2eeUserTransaction"><propertyname="transactionTimeout"value="300"/></bean><beanid="transactionManager"class="org.springframework.transaction.jta.JtaTransactionManager"depends-on="atomikosTransactionManager,atomikosUserTransaction"><propertyname="transactionManager"ref="atomikosTransactionManager"/><propertyname="userTransaction"ref="atomikosUserTransaction"/><propertyname="allowCustomIsolationLevels"value="true"/></bean></beans>

Things to note in Spring configuration:

We are instructing Spring to use a JTA transaction manager (jta-transaction-manager configuration element).

We define a couple of beans to represent the both database connections (beans dataBase1 and dataBase2). The datasource connections are using com.mysql.jdbc.jdbc2.optional.MysqlXADataSource class.

We are defining two Atomikos datasources (dataSource1 and dataSource2) that will be coupled with the respective database connections we just defined.

We are also defining a couple of Entity Manager factories each one associated with the respective Atomikos datasource and the Persistence Units we defined in the previous section.

Finally we define the Atomikos JTA Transaction Manager and the Atomikos JTA User Transaction that will be both used by The Spring JTA Transaction Manager.

If you need more information on the JTA Transaction Manager and JTA User Transaction roles in a JTA distributed transaction you should search the Internet for additional documentation as there is plenty available.

Testing the example

Now we define a simple servlet to test the configuration:

Testing servlet
package com.byteslounge.spring.tx.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.HttpRequestHandler;

import com.byteslounge.spring.tx.entity.TableOne;
import com.byteslounge.spring.tx.entity.TableTwo;
import com.byteslounge.spring.tx.service.TransactionalService;

@Component("testServlet")
public class TestServlet implements HttpRequestHandler {

  @Autowired
  private TransactionalService transactionalService;

  @Override
  public void handleRequest(
      HttpServletRequest req,
      HttpServletResponse resp)
         throws ServletException, IOException {

    TableOne tableOne = new TableOne();
    tableOne.setValue("value1");

    TableTwo tableTwo = new TableTwo();
    tableTwo.setValue("value2");

    try {
      transactionalService.persist(tableOne, tableTwo);
    } catch (Exception e) {
      e.printStackTrace();
    }

  }

}

Note that we are implementing Spring HttpRequestHandler interface so we are able to use Spring dependency injection in the servlet itself, but we will not detail this subject in the current tutorial.

After the servlet execution we will observe that neither of the records are inserted in TABLE_ONE and TABLE_TWO. This is because the second transaction is explicitly throwing an Exception as we configured it in the previous sections and so the global transaction is rollback.

Make the transaction commit

In order to make the transaction to successfully commit we just need to remove the explicit exception throwing in Datasource 2DAO:

Modified TableTwoDaoImpl.java
package com.byteslounge.spring.tx.dao.impl;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Service;

import com.byteslounge.spring.tx.dao.TableTwoDao;
import com.byteslounge.spring.tx.entity.TableTwo;

@Service
public class TableTwoDaoImpl implements TableTwoDao {

  private EntityManager entityManager;

  @PersistenceContext(unitName="PersistenceUnit2")
  public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
  }

  @Override
  public void save(TableTwo tableTwo) throws Exception {
    // Exception throwing is removed
    entityManager.persist(tableTwo);
  }

}

Downloadable sample

You may find the complete example source code as a downloadable resource at the end of this page. The downloadable sample is explicitly throwing the exception so you may observe the behaviour of global transaction rollback. Change it in order to suit your needs.

Download source code from this article

 
 
FAQ:
    Q:

Messages:
Unable to access TransactionManager or UserTransaction to make physical transaction delegate
File:    org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorImpl.java
Line number:    239

Stacktraces
org.hibernate.resource.transaction.backend.jta.internal.JtaPlatformInaccessibleException:
Unable to access TransactionManager or UserTransaction to make physical transaction delegate

Error message: html page inforamtion

A:

1) POM

<!-- https://mvnrepository.com/artifact/com.atomikos/transactions-hibernate3 -->
    <dependency>
        <groupId>com.atomikos</groupId>
        <artifactId>transactions-hibernate3</artifactId>
        <version>4.0.6</version>
    </dependency>

Hibernate3

-》》

<!-- https://mvnrepository.com/artifact/com.atomikos/transactions-hibernate4 -->
    <dependency>
        <groupId>com.atomikos</groupId>
        <artifactId>transactions-hibernate4</artifactId>
        <version>4.0.6</version>
    </dependency>

Hibernate4

2) Persistence

               <property name="hibernate.transaction.manager_lookup_class"
                   value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup" />

Hibernate3

->>

               <property name="hibernate.transaction.manager_lookup_class"
                   value="com.atomikos.icatch.jta.hibernate4.TransactionManagerLookup" />

Hibernate4

Important:

<property name="hibernate.transaction.jta.platform"
                   value="com.atomikos.icatch.jta.hibernate4.AtomikosPlatform" />

Spring JTA multiple resource transactions in Tomcat with Atomikos example的更多相关文章

  1. Spring JTA multiple resource transactions in Tomcat with Atomikos example--转载

    原文地址:http://www.javacodegeeks.com/2013/07/spring-jta-multiple-resource-transactions-in-tomcat-with-a ...

  2. spring boot 加载web容器tomcat流程源码分析

    spring boot 加载web容器tomcat流程源码分析 我本地的springboot版本是2.5.1,后面的分析都是基于这个版本 <parent> <groupId>o ...

  3. 分布式事务操作之Spring+JTA

    什么是分布式事务?在网上找了一段比较容易理解的"定义". 分布式事务是指事务的参与者.支持事务的服务器.资源管理器以及事务管理器分别位于分布系统的不同节点之上,在两个或多个网络计算 ...

  4. Spring Injection with @Resource, @Autowired and @Inject

    August 1st, 2011 by David Kessler Overview I’ve been asked several times to explain the difference b ...

  5. spring注入注解@Resource和@Autowired

    一.@Autowired和@Qualifier @Autowired是自动注入的注解,写在属性.方法.构造方法上,会按照类型自动装配属性或参数.该注解,可以自动装配接口的实现类,但前提是spring容 ...

  6. TN035: Using Multiple Resource Files and Header Files with Visual C++

    TN035: Using Multiple Resource Files and Header Files with Visual C++ This note describes how the Vi ...

  7. Spring JTA应用JOTM & Atomikos III Atomikos

    前面简单介绍了JOTM如何在Spring中配置,并如何使用它的JTA事务,本节将介绍Atomikos如何与Spring集成,并使用它的JTA事务. Atomikos,是一个基于Java的开源事务管理器 ...

  8. Spring JTA应用JOTM & Atomikos I Application

    关于Spring JTA的介绍非常多了,这里就不再一再阐述其优越性怎么怎么了,直接开始正题.一个大致的需求如下,用户在进行增删改操作时,会同时更新2至3个数据库的数据表,操作需要事务来包裹,以便在操作 ...

  9. Java 本地开发环境搭建(框架采用 Spring+Spring MVC+Hibernate+Jsp+Gradle+tomcat+mysql5.6)

    项目搭建采用技术栈为:Spring+Spring MVC+Hibernate+Jsp+Gradle+tomcat+mysql5.6 搭建环境文档目录结构说明: 使用Intellj Idea 搭建项目过 ...

随机推荐

  1. Socket层实现系列 — 睡眠驱动的同步等待

    主要内容:Socket的同步等待机制,connect和accept等待的实现. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd 概述 socket上定义了 ...

  2. jsp自动编译机制

    总的来说,Jasper的自动检测实现的机制比较简单,依靠某后台线程不断检测JSP文件与编译后的class文件的最后修改时间是否相同,若相同则认为没有改动,但倘若不同则需要重新编译.实际上由于在Tomc ...

  3. 分布式进阶(九)Ubuntu下使用nsenter进入Docker容器

    使用nsenter进入Docker容器 Docker容器运行后,如何进入容器进行操作呢?起初我是用SSH.如果只启动一个容器,用SSH还能应付,只需要将容器的22端口映射到本机的一个端口即可.当我启动 ...

  4. javascript语法之Date对象与小案例

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. rpcz VC2010 构建

    rpcz VC2010 构建 rpcz 是应用ZeroMQ和Protobuf开发的RPC. 见: https://github.com/reinferio/rpcz 及 https://code.go ...

  6. 手把手带你画一个漂亮蜂窝view Android自定义view

    上一篇做了一个水波纹view  不知道大家有没有动手试试呢点击打开链接 这个效果做起来好像没什么意义,如果不加监听回调 图片就能直接替代.写这篇博客的目的是锻炼一下思维能力,以更好的面多各种自定义vi ...

  7. 关于oracle表名区分大小写的问题

    oracle不是区分大小写的,是建表的时候是没有去掉双引号.   CREATE TABLE TableName(id number); //虽然写的时候是有大写和小写,但是在数据库里面是不区分的.   ...

  8. 断言(Assertion)需要注意的一个地方

    因为断言只在debug构建中有效,所以它是中关重要的去避免运行任何代码或调用任何方法在断言条件中,而这些代码或方法会影响程序的状态. 否则程序的行为将在debug和release构建中变得不一致,这显 ...

  9. 鹅场offer已Get,下周签约,终于能静下心来总结总结

    2015年9月20号下午,接到腾讯总部的电话,确定了offer相关信息,算是正式get了鹅场的offer,坐等下个周一周二的签约会. 心路篇 2015年2月:已经2月份了,自己在大学的时光已经来到了比 ...

  10. 如何用代码禁用SpriteBuilder中创建的关节

    这个目标是临时的禁用距离关节(distance joint). 不幸的是,你只可以无效化(通过删除的方式)一个关节. 所以,你必须通过代码创建一个新的距离关节实例并且赋予它之前删除关节(在Sprite ...