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

时间:2022-05-06 06:33:05

一、使用注解可以解决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. Macosx 安装 ionic 成功教程

    一.首先介绍一下ionic ionic是一个用来开发混合手机应用的,开源的,免费的代码库.可以优化html.css和js的性能,构建高效的应用程序,而且还可以用于构建Sass和AngularJS的优化 ...

  2. 还是畅通工程&lbrack;HDU1233&rsqb;

    还是畅通工程 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...

  3. IOS响应式编程框架ReactiveCocoa&lpar;RAC&rpar;使用示例

    ReactiveCocoa是响应式编程(FRP)在iOS中的一个实现框架,它的开源地址为:https://github.com/ReactiveCocoa/ReactiveCocoa# :在网上看了几 ...

  4. 如何利用phpize在生产环境中为php添加新的扩展php-bcmath

    在日常的开发当中,随着开发的功能越来越复杂.对运行环境的要求也就随着需求的变化需要不断地更新和变化.一个在线的生产系统不可能一开始就满足了所有的运行依赖,因此动态地添加依赖就显得比较必要了.如果你的应 ...

  5. UVA 10779 Collectors Problem&lpar;最大流&rpar;

    这个题是很难往网络流上面构思的... 从s向每个物品增加容量为Bob拥有数的弧,然后从每个物品向t增加容量为1的弧(代表种类个数).这时候跑最大流的话,得到的肯定是Bob拥有的初始种类数.那么交换后的 ...

  6. Linq中的常用方法

    System.Linq System.Linq.Enumerable  类 Range Repeat Reverse Select Where Sum Zip Aggregate Count Firs ...

  7. 第1阶段——uboot分析之启动函数bootm命令 &lpar;9&rpar;

    本节主要学习: 详细分析UBOOT中"bootcmd=nand read.jffs2 0x30007FC0 kernel;bootm 0x30007FC0"中怎么实现bootm命令 ...

  8. Kitematic - VirtualBox is not installed&period; Docker for windows 10

    Kitematic - VirtualBox is not installed. Docker for windows 10 https://github.com/docker/kitematic/i ...

  9. 李洪强iOS之集成极光推送二iOS 证书 设置指南

    李洪强iOS之集成极光推送二iOS 证书 设置指南 创建应用程序ID 登陆 iOS Dev Center 选择进入iOS Provisioning Portal. 在 iOS Provisioning ...

  10. thinkjs——redis

    前言: 后台某些操作的时候会用到缓存:比如用户登录或者校验次数的情景.而本次遇见的状况就是在点击“推送”按钮的时候,需要判断缓存中是否有其值,并将其次数限制为固定值. 过程: 刚听到此需求的时候,首先 ...