一、使用注解可以解决JavaBean和数据库中表名不一致、字段名不一致、字段数量不一致的问题。

  1.Sun公司给jdbc提供的注解

  @Table、@Column、@Id、@OneToMany、@OneToOne、@ManyToMany

  2.小练习:对JavaBean的某些字段进行注解、对JavaBean名称进行注解以匹配数据库表名。

   Person.java

package com.kdyzm.domain;

import javax.persistence.Column;
import javax.persistence.Table;
/*
* 使用注解可以解决数据库表名和类名不一致的问题,可以解决字段名不匹配的问题,可以解决字段数量不匹配的问题
*/
@Table(name="user")//实际的表名为user,而不是person
public class Person {
@Column(name="id")
private String personid;
@Column(name="name")
private String personname;
@Column(name="age")
private int personage; private String personAddress;//该字段在数据库表中斌不存在。 public Person() {
}
public Person(String personid, String personname, int personage,
String personAddress) {
this.personid = personid;
this.personname = personname;
this.personage = personage;
this.personAddress = personAddress;
} public String getPersonid() {
return personid;
}
public void setPersonid(String personid) {
this.personid = personid;
}
public String getPersonname() {
return personname;
}
public void setPersonname(String personname) {
this.personname = personname;
}
public int getPersonage() {
return personage;
}
public void setPersonage(int personage) {
this.personage = personage;
}
public String getPersonAddress() {
return personAddress;
}
public void setPersonAddress(String personAddress) {
this.personAddress = personAddress;
}
@Override
public String toString() {
return "Person [personid=" + personid + ", personname=" + personname
+ ", personage=" + personage + "]";
}
}

Person.java

   UserDao.java

 package com.kdyzm.dao;

 import com.kdyzm.dbutils.DataSourceUtils_c3p0;
import com.kdyzm.dbutils.QueryRunner;
import com.kdyzm.domain.Person; //注解在数据库中的使用方法
public class UserDao {
public static void main(String[] args) throws Exception {
Person p=new Person();
p.setPersonid("12455324");
p.setPersonname("小强");
p.setPersonage(24);
p.setPersonAddress("山东理工大学"); QueryRunner run=new QueryRunner(DataSourceUtils_c3p0.getDataSource());
run.save(p);
}
}

  重写QueryRunner类(dbutils.jar包)

package com.kdyzm.dbutils;
/*
* 重写QueryRunner类,将异常全部捕捉
* 新增加一个方法save,这个方法利用反射机制可以省去书写sql的麻烦。
*/
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; import javax.persistence.Column;
import javax.persistence.Table;
import javax.sql.DataSource; import org.apache.commons.dbutils.ResultSetHandler; public class QueryRunner extends org.apache.commons.dbutils.QueryRunner{
public <T>T save(T t)throws Exception
{
Class<?> cls=t.getClass();
/*
* 获取表名,这里理应当先进行判断是否存在注解即调用isAnnotationPresents方法,
* 但是因为一定存在注解,所以不进行判断了
*/
Table table=cls.getAnnotation(Table.class);
//首先获取表名
String tableName=table.name(); //组成sql语句,这是重中自重
String sql="insert into "+tableName;
String columns="(";//拼接字段名称
String values="values(";//拼接值 //获取所有声明的字段名称
Field[]fields=cls.getDeclaredFields();
for(Field field:fields)
{
if(field.isAnnotationPresent(Column.class))//如果进行了注解的话,这句话是解决字段数量不匹配的核心
{
field.setAccessible(true);//设置可以暴力访问
String columnName=field.getName();//本来的字段名
Column column=field.getAnnotation(Column.class);
//优先考虑有没有注解的字段名,如果没有注解的话则使用原来的字段名否则使用注解声明的字段名
if(column.name()!=null||!column.name().equals(""))//如果有注解的话使用注解上声明的字段名
{
columnName=column.name();
}
//获取列值
Object value=field.get(t); if(columns.equals("("))
{
columns+=columnName;
if(value instanceof String)
{
values+="'"+value+"'";
}
else
{
values+=value;
}
}
else
{
columns+=","+columnName;
if(value instanceof String)
{
values+=",'"+value+"'";
}
else
{
values+=","+value;
}
}
}
}
columns+=") ";
values+=")";
sql+=columns;
sql+=values;
System.out.println(sql);
update(sql);
return t;
}
public QueryRunner() {
super();
}
public QueryRunner(boolean pmdKnownBroken) {
super(pmdKnownBroken);
}
public QueryRunner(DataSource ds, boolean pmdKnownBroken) {
super(ds, pmdKnownBroken);
}
public QueryRunner(DataSource ds) {
super(ds);
}
@Override
public int[] batch(Connection conn, String sql, Object[][] params)
throws SQLException {
return super.batch(conn, sql, params);
}
@Override
public int[] batch(String sql, Object[][] params) throws SQLException{
return super.batch(sql, params);
}
@Override
public <T> T insert(Connection conn, String sql, ResultSetHandler<T> rsh,
Object... params) throws SQLException {
return super.insert(conn, sql, rsh, params);
}
@Override
public <T> T insert(Connection conn, String sql, ResultSetHandler<T> rsh)
throws SQLException {
return super.insert(conn, sql, rsh);
}
@Override
public <T> T insert(String sql, ResultSetHandler<T> rsh, Object... params)
throws SQLException {
return super.insert(sql, rsh, params);
}
@Override
public <T> T insert(String sql, ResultSetHandler<T> rsh)
throws SQLException {
return super.insert(sql, rsh);
}
@Override
public <T> T insertBatch(Connection conn, String sql,
ResultSetHandler<T> rsh, Object[][] params) throws SQLException {
return super.insertBatch(conn, sql, rsh, params);
}
@Override
public <T> T insertBatch(String sql, ResultSetHandler<T> rsh,
Object[][] params) throws SQLException {
return super.insertBatch(sql, rsh, params);
}
@Override
public <T> T query(Connection conn, String sql, Object param,
ResultSetHandler<T> rsh) throws SQLException {
return super.query(conn, sql, param, rsh);
}
@Override
public <T> T query(Connection conn, String sql, Object[] params,
ResultSetHandler<T> rsh) throws SQLException {
return super.query(conn, sql, params, rsh);
}
@Override
public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh,
Object... params) throws SQLException {
return super.query(conn, sql, rsh, params);
} @Override
public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh)
throws SQLException {
return super.query(conn, sql, rsh);
} @Override
public <T> T query(String sql, Object param, ResultSetHandler<T> rsh)
throws SQLException {
return super.query(sql, param, rsh);
} @Override
public <T> T query(String sql, Object[] params, ResultSetHandler<T> rsh)
throws SQLException {
return super.query(sql, params, rsh);
} @Override
public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params)
throws SQLException {
return super.query(sql, rsh, params);
} @Override
public <T> T query(String sql, ResultSetHandler<T> rsh) throws SQLException {
return super.query(sql, rsh);
} @Override
public int update(Connection conn, String sql, Object... params)
throws SQLException {
return super.update(conn, sql, params);
} @Override
public int update(Connection conn, String sql, Object param)
throws SQLException {
return super.update(conn, sql, param);
} @Override
public int update(Connection conn, String sql) throws SQLException {
return super.update(conn, sql);
} @Override
public int update(String sql, Object... params) throws SQLException {
return super.update(sql, params);
} @Override
public int update(String sql, Object param) throws SQLException {
return super.update(sql, param);
} @Override
public int update(String sql) throws SQLException {
return super.update(sql);
} @Override
protected void close(Connection conn) throws SQLException {
super.close(conn);
} @Override
protected void close(ResultSet rs) throws SQLException {
super.close(rs);
} @Override
protected void close(Statement stmt) throws SQLException {
super.close(stmt);
} @Override
public void fillStatement(PreparedStatement arg0, Object... arg1)
throws SQLException {
super.fillStatement(arg0, arg1);
} @Override
public void fillStatementWithBean(PreparedStatement arg0, Object arg1,
PropertyDescriptor[] arg2) throws SQLException {
super.fillStatementWithBean(arg0, arg1, arg2);
} @Override
public void fillStatementWithBean(PreparedStatement arg0, Object arg1,
String... arg2) throws SQLException {
super.fillStatementWithBean(arg0, arg1, arg2);
} @Override
public DataSource getDataSource() {
return super.getDataSource();
} @Override
public boolean isPmdKnownBroken() {
return super.isPmdKnownBroken();
} @Override
protected Connection prepareConnection() throws SQLException {
return super.prepareConnection();
} @Override
protected PreparedStatement prepareStatement(Connection conn, String sql,
int returnedKeys) throws SQLException {
return super.prepareStatement(conn, sql, returnedKeys);
} @Override
protected PreparedStatement prepareStatement(Connection conn, String sql)
throws SQLException {
return super.prepareStatement(conn, sql);
} @Override
protected void rethrow(SQLException cause, String sql, Object... params)
throws SQLException {
super.rethrow(cause, sql, params);
} @Override
protected ResultSet wrap(ResultSet rs) {
return super.wrap(rs);
}
}

QueryRunner.java

  重写之后的类中多出了一个方法:save方法,该方法接受一个JavaBean参数,并使用反射对该JavaBean进行解析,得到该JavaBean中符合要求的字段,并得到每个字段对应的值,关键是凭借sql语句的过程。

  C3p0数据库连接池工具类:

package com.kdyzm.dbutils;
/**
* 数据库连接池工具类。
*/
import java.sql.Connection;
import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class DataSourceUtils_c3p0 {
private static ThreadLocal<Connection>tl=new ThreadLocal<Connection>();
private static DataSource ds=null;
static{
ds=new ComboPooledDataSource("namedconfig");
}
public static Connection getConnection(){
Connection conn=tl.get();
if(conn==null)
{
try {
conn=ds.getConnection();
tl.set(conn);//这句代码十分重要,千万不能忘(将当前线程和请求的Connection对象绑定)
} catch (SQLException e) {
e.printStackTrace();
}
}
return conn;
}
public static DataSource getDataSource(){
return ds;
}
public static void remove(){
tl.remove();//这句代码也十分重要,千万不能忘掉,将会在TransactionFilter中调用
}
}

DataSourceUtils_c3p0.java

  c3p0数据库连接池配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默认配置,只可以出现一次 -->
<default-config>
<!-- 连接超时设置30秒 -->
<property name="checkoutTimeout">30000</property>
<!-- 30秒检查一次connection的空闲 -->
<property name="idleConnectionTestPeriod">30</property>
<!--初始化的池大小 -->
<property name="initialPoolSize">2</property>
<!-- 最多的一个connection空闲时间 -->
<property name="maxIdleTime">30</property>
<!-- 最多可以有多少个连接connection -->
<property name="maxPoolSize">10</property>
<!-- 最少的池中有几个连接 -->
<property name="minPoolSize">2</property>
<!-- 批处理的语句-->
<property name="maxStatements">50</property>
<!-- 每次增长几个连接 -->
<property name="acquireIncrement">3</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">
<![CDATA[jdbc:mysql://10.6.112.200:3306/test?useUnicode=true&characterEncoding=UTF-8]]>
</property>
<property name="user">root</property>
<property name="password">5a6f38</property>
</default-config> <named-config name="namedconfig">
<!-- 连接超时设置30秒 -->
<property name="checkoutTimeout">30000</property>
<!-- 30秒检查一次connection的空闲 -->
<property name="idleConnectionTestPeriod">30</property>
<!--初始化的池大小 -->
<property name="initialPoolSize">2</property>
<!-- 最多的一个connection空闲时间 -->
<property name="maxIdleTime">30</property>
<!-- 最多可以有多少个连接connection -->
<property name="maxPoolSize">4</property>
<!-- 最少的池中有几个连接 -->
<property name="minPoolSize">2</property>
<!-- 批处理的语句-->
<property name="maxStatements">50</property>
<!-- 每次增长几个连接 -->
<property name="acquireIncrement">2</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">
<![CDATA[jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8]]>
</property>
<property name="user">root</property>
<property name="password">5a6f38</property>
</named-config>
</c3p0-config>

c3p0-config.xml

  3.运行结果:

2015-7-1 20:10:05 com.mchange.v2.log.slf4j.Slf4jMLog$Slf4jMLogger$InfoLogger log
信息: MLog clients using slf4j logging.
2015-7-1 20:10:07 com.mchange.v2.log.slf4j.Slf4jMLog$Slf4jMLogger$InfoLogger log
信息: Initializing c3p0-0.9.5 [built 02-January-2015 13:25:04 -0500; debug? true; trace: 10]
insert into user(id,name,age) values('12455324','小强',24)
2015-7-1 20:10:08 com.mchange.v2.log.slf4j.Slf4jMLog$Slf4jMLogger$InfoLogger log
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 2, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 30000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> namedconfig, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceUseNamedDriverClass -> false, identityToken -> 2s4ze59akeetzj1p6tfdu|a32b, idleConnectionTestPeriod -> 30, initialPoolSize -> 2, jdbcUrl -> jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 30, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 4, maxStatements -> 50, maxStatementsPerConnection -> 0, minPoolSize -> 2, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]

数据库中已经多出了一条记录。表名已经保存到数据库中成功。

  4.源代码:https://github.com/kdyzm/day24_2

二、反射+注解+动态代理在事务中的应用service层

  1.代理

    代理就使用一种方法在一个对象调用一个方法的时候拦截该方法的执行并改为执行另外一个动作。

  2.代理的核心类

    (1)Proxy:在内存中生成该接口的一个实例。

    (2)InvocationHandler:执行句柄,在执行代理类的方法的时候,该句柄会拦截所有代理类的方法。

  3.使用代理类的要求:被代理类必须至少实现一种接口。

  4.对List进行代理。

package com.kdyzm.demo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List; /**
* 演示对List进行代理,只能对List进行代理。
* @author kdyzm
*
*/
public class ProxyForListDemo {
public static void main(String[] args) {
final List<String>list=new ArrayList<String>();
Object proxy=Proxy.newProxyInstance(ProxyForListDemo.class.getClassLoader(),
new Class[]{List.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println(method.getName()+"方法被调用!");
return method.invoke(list, args);
}
});
@SuppressWarnings("unchecked")
List<String>l=(List<String>) proxy;
l.add("小强!");
System.out.println(l);
}
}

  运行结果:

add方法被调用!
toString方法被调用!
[小强!]

三、对所实现接口的类进行代理

  1.使用一个类封装代理的过程。该类实现了InvocationHandler接口。

package com.kdyzm.demo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; /*
* 演示对所有拥有接口的类进行代理,并且该类实现了InvocationHandler接口。
* 这种方式是推荐的代理方式。
*/
public class ProxyForAllClassHasInterface implements InvocationHandler{
private Object src;
private ProxyForAllClassHasInterface(Object src)
{
this.src=src;
}
public static Object factory(Object src)
{
Object aim=Proxy.newProxyInstance(ProxyForAllClassHasInterface.class.getClassLoader(),
src.getClass().getInterfaces(),
new ProxyForAllClassHasInterface(src));
return aim;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println(method.getName()+"方法被调用ProxyForAllClassHasInterface!");
return method.invoke(src, args);//调用src的方法。
}
}

  这种方式是推荐的使用方式。

   2.测试该工具类。

package com.kdyzm.demo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; /*
* 对ProxyForAllClassHasInterface类进行测试!
*/
public class Test {
public static void main(String[] args) {
List<String>list=new ArrayList<String>();
list=(List<String>) ProxyForAllClassHasInterface.factory(list);
list.add("你好,小强!");
System.out.println(list); Map<String,String>map=new HashMap<String,String>();
map=(Map<String, String>) ProxyForAllClassHasInterface.factory(map);
map.put("12110501001", "小强");
System.out.println(map);
}
}

  3.运行结果

add方法被调用ProxyForAllClassHasInterface!
toString方法被调用ProxyForAllClassHasInterface!
[你好,小强!]
put方法被调用ProxyForAllClassHasInterface!
toString方法被调用ProxyForAllClassHasInterface!
{12110501001=小强}

四、反射+注解+动态代理在事务中的应用service层

  1.解决的问题:事务使用OSIV模式并不高效,而且结构比较复杂,为了解决这个问题,可以使用反射+注解+动态代理的方式,这将称为最终的解决方式。

  使用该方式的灵活性极高,事务的处理过程在service层解决,但是在serviece层的代码中又看不出来,实际上的事务处理在代理类中实现,service是否开启事务,仅仅只需要一句代码就可以解决。

  2.核心类:代理service的ProxyForTransactionService类。

package com.kdyzm.dbutils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection; import com.kdyzm.demo.ProxyForAllClassHasInterface;
import com.kdyzm.myannotation.Transactionflag; /*
* 对Service类进行代理,拦截特定的方法并进行修改,实现InvocationHandler接口是经典的做法。
* 该类可以放在工具类中。
*/
public class ProxyForTransactionService implements InvocationHandler{
private Object src;
private ProxyForTransactionService(Object src)
{
this.src=src;
}
public static Object factory(Object src)
{
Object aim=Proxy.newProxyInstance(ProxyForAllClassHasInterface.class.getClassLoader(),
src.getClass().getInterfaces(),
new ProxyForTransactionService(src));
return aim;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Connection connection=null;
Object returnValue=null;
if(!method.isAnnotationPresent(Transactionflag.class))//首先判断是否是经过注解的方法,如果是没有经过注解的方法则表明不需要开启事务!
{
System.out.println("不需要开启事务的方法:"+method.getName());
return method.invoke(src, args);
}
System.out.println("需要开启事务的方法:"+method.getName());
try
{
//获取连接
connection=DataSourceUtils_c3p0.getConnection();
//设置事务的开始
connection.setAutoCommit(false);
System.out.println("已经开启事务!");
//调用方法
method.invoke(src, args);
connection.commit();
System.out.println("提交!结束事务!");
}
catch(Exception e)
{
connection.rollback();
System.out.println("回滚!结束事务!");
throw e;//为什么能抛,因为Throwable是Exception的父类。
}
finally
{
connection.close();
DataSourceUtils_c3p0.remove();
}
return returnValue;
} }

  2.要对service层的类进行代理,这些类必须至少实现一个接口,所以需要定义一个接口。

package com.kdyzm.interfaces;

import com.kdyzm.myannotation.Transactionflag;

public interface TransactionInterface {
@Transactionflag//表示该方法需要使用事务
public void save();//定义save事务解决方法。
//不加注解表示该方法不需要使用事务。
public void query();
}

  3.实现该接口的类看不出有事务的处理,但实际上已经对某些方法开启了事务。

package com.kdyzm.service;

import com.kdyzm.dao.Dao1;
import com.kdyzm.dao.Dao2;
import com.kdyzm.interfaces.TransactionInterface; public class SaveService implements TransactionInterface{
Dao1 dao1=new Dao1();
Dao2 dao2=new Dao2();
@Override
public void save()
{
dao1.save();
dao2.save();
}
@Override
public void query() {
dao1.query();
}
}

  4.自定义一个注解对接口上的某些方法进行注解。

package com.kdyzm.myannotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(value=RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD})
public @interface Transactionflag { }

  5.测试

  (1)当没有异常发生的时候

  控制台输出结果:

需要开启事务的方法:save
七月 01, 2015 9:05:20 下午 com.mchange.v2.log.MLog
信息: MLog clients using java 1.4+ standard logging.
七月 01, 2015 9:05:21 下午 com.mchange.v2.c3p0.C3P0Registry
信息: Initializing c3p0-0.9.5 [built 02-January-2015 13:25:04 -0500; debug? true; trace: 10]
七月 01, 2015 9:05:21 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 2, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 30000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> namedconfig, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceUseNamedDriverClass -> false, identityToken -> 2s4ze59akgdv042f54zv|142f828, idleConnectionTestPeriod -> 30, initialPoolSize -> 2, jdbcUrl -> jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 30, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 4, maxStatements -> 50, maxStatementsPerConnection -> 0, minPoolSize -> 2, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
已经开启事务!
提交!结束事务!

  检查数据库,多出了两条记录。

  (2)当有异常发生时。

需要开启事务的方法:save
七月 01, 2015 9:07:05 下午 com.mchange.v2.log.MLog
信息: MLog clients using java 1.4+ standard logging.
七月 01, 2015 9:07:05 下午 com.mchange.v2.c3p0.C3P0Registry
信息: Initializing c3p0-0.9.5 [built 02-January-2015 13:25:04 -0500; debug? true; trace: 10]
七月 01, 2015 9:07:05 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 2, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 30000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> namedconfig, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceUseNamedDriverClass -> false, identityToken -> 2s4ze59akgg3q3p33eio|142f828, idleConnectionTestPeriod -> 30, initialPoolSize -> 2, jdbcUrl -> jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 30, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 4, maxStatements -> 50, maxStatementsPerConnection -> 0, minPoolSize -> 2, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
已经开启事务!
回滚!结束事务!

七月 01, 2015 9:07:06 下午 org.apache.catalina.core.StandardWrapperValve invoke
各种异常信息略。

  检查数据库,一条记录也没有。

  5.怎样判别一个方法是否需要开启事务?比如查询操作就不需要开启事务。

  解决方法:对需要进行事务处理的方法进行注解,在代理工具类中进行判断。

  6.源代码:https://github.com/kdyzm/day24_3

  7.注意事项:代理之后的对象强制转换的结果一定是被代理类的接口的实例,而不是被代理类的实例。这点是十分重要的。如果强转成被代理类的实例,则一定会强制转换异常的错误。

  

【Java EE 学习 24 下】【注解在数据库开发中的使用】【反射+注解+动态代理在事务中的应用service层】的更多相关文章

  1. 【Java EE 学习 17 下】【数据库导出到Excel】【多条件查询方法】

    一.导出到Excel 1.使用DatabaseMetaData分析数据库的数据结构和相关信息. (1)测试得到所有数据库名: private static DataSource ds=DataSour ...

  2. 【Java EE 学习 24 上】【注解详解】

    一.注解 1.所有的注解都是类. 2.所有的注解都是Annotation接口的子类. 接口摘要 Annotation 所有 annotation 类型都要扩展的公共接口. 3.定义方式 public ...

  3. 【Java EE 学习 67 下】【OA项目练习】【SSH整合JBPM工作流】【JBPM项目实战】

    一.SSH整合JBPM JBPM基础见http://www.cnblogs.com/kuangdaoyizhimei/p/4981551.html 现在将要实现SSH和JBPM的整合. 1.添加jar ...

  4. 【Java EE 学习 79 下】【动态SQL】【mybatis和spring的整合】

    一.动态SQL 什么是动态SQL,就是在不同的条件下,sql语句不相同的意思,曾经在“酒店会员管理系统”中写过大量的多条件查询,那是在SSH的环境中,所以只能在代码中进行判断,以下是其中一个多条件查询 ...

  5. 【Java EE 学习 69 下】【数据采集系统第一天】【实体类分析和Base类书写】

    之前SSH框架已经搭建完毕,现在进行实体类的分析和Base类的书写.Base类是抽象类,专门用于继承. 一.实体类关系分析 既然是数据采集系统,首先调查实体(Survey)是一定要有的,一个调查有多个 ...

  6. 【Java EE 学习 74 下】【数据采集系统第六天】【使用Jfreechart的统计图实现】【将JFreechart整合到项目中】

    之前说了JFreechart的基本使用方法,包括生成饼图.柱状统计图和折线统计图的方法.现在需要将其整合到数据采集系统中根据调查结果生成三种不同的统计图. 一.统计模型的分析和设计 实现统计图显示的流 ...

  7. 【Java EE 学习 35 下】【struts2】【struts2文件上传】【struts2自定义拦截器】【struts2手动验证】

    一.struts2文件上传 1.上传文件的时候要求必须使得表单的enctype属性设置为multipart/form-data,把它的method属性设置为post 2.上传单个文件的时候需要在Act ...

  8. 【Java EE 学习 82 下】【MAVEN整合Eclipse】【MAVEN的一些高级概念】

    一.MAVEN整合Eclipse MAVEN是非常优秀,但是总是要开命令行敲命令是比较不爽的,我们已经习惯了使用IDE,所以还有一种将MAVEN整合到Eclipse的方法. 详情查看:http://w ...

  9. 【Java EE 学习 29 下】【JDBC编程中操作Oracle数据库】【调用存储过程的方法】

    疑问:怎样判断存储过程执行之后返回值是否为空. 一.连接oracle数据库 1.需要的jar包:在安装的oracle中就有,所以不需要到官网下载,我的oracle11g下:D:\app\kdyzm\p ...

随机推荐

  1. VsFtpd配置文件详解

    1.默认配置:1>允许匿名用户和本地用户登陆.     anonymous_enable=YES     local_enable=YES2>匿名用户使用的登陆名为ftp或anonymou ...

  2. 如何实现CDN的ns智能解析和动手验证Akamai的实现

    1.什么是ns智能解析 通常CDN业务中,智能解析域名,是根据请求方ip的不同给出不同的A记录. 而ns智能解析,是根据请求方ip的不同让他去不同的ns上解析域名,把ns推向离用户更近的边缘节点来缩短 ...

  3. 【转】精选30个优秀的CSS技术和实例

    今天,我为大家收集精选了30个使用纯CSS完成的强大实践的优秀CSS技术和实例,您将在这里发现很多与众不同的技术,比如:图片集.阴影效果.可扩展按钮.菜单等-这些实例都是使用纯CSS和HTML实现的. ...

  4. 开发unity DLL插件

    最近开发一款设备的SDK,想着要开发unity版本,怎么做呢?首先想到的就是在外部编写相关的驱动程序然后集成成几个dll作为unity的SDK使用了.So,我就开始了unity外部插件的研究之旅了. ...

  5. Extjs 学习总结-代理

    代理(proxy)是用来加载和存取Model 数据的.开发中一般配合Store完成工作,不会直接操作代理. 代理分为两大类: 客户端代理 服务器代理 客户端代理主要完成与浏览器本地存储数据相关的工作. ...

  6. tail -f 和 -F 的用法

    tail -f 和 -F 的用法  Tai 2010-08-16 16:03:18 -f 是--follow[=HOW]的缩写, 可以一直读文件末尾的字符并打印出来."[=HOW]" ...

  7. IAP

    release_check_url := "https://buy.itunes.apple.com/verifyReceipt" debug_check_url := " ...

  8. JAVA关键字与保留字说明及使用

    1.abstract 2.boolean 3.break 4.byte 5.case 6.catch 7.char 8.class 9.continue 10.default 11.do 12.dou ...

  9. codevs1021 玛丽卡

    题目描述 Description 麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复. 因为她和他们不住在同一个城市,因此她开始准备她的长途旅行. 在这个国家中每两个城市之间最多只有一条路相通,并且我们 ...

  10. 用mixin引入模块后, 方法重名的解析方法

    关于mixin, 经常被问到一个问题是, 方法查找是如何处理的? 特别地, 如果类, 父类, 以及类所包含的mixin中, 都定义有相同名字的方法时, 会发生什么? 答案是, ruby首先会从对象的直 ...