JdbcUtils工具类
在Dao层操作数据库时,需要频繁的得到数据库链接,所以自定义一个数据库的工具类JdbcUtils.java有两种方案:1、线程不安全的数据库工具类2、线程安全的数据库工具类代码如下1、线程不安全的数据库工具类db.propertiesdriver=com.mysql.jdbc.Driverurl=jdbc\:mysql\://localhost\:3306/test
·
在Dao层操作数据库时,需要频繁的得到数据库链接,所以自定义一个数据库的工具类JdbcUtils.java
有两种方案:
1、线程不安全的数据库工具类
2、线程安全的数据库工具类
代码如下
1、线程不安全的数据库工具类
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc\:mysql\://localhost\:3306/test
username=root
password=mysqladmin
JdbcUtils.java
public class JdbcUtils{
private static Properties config = new Properties(); //单例模式
static{ //静态代码块,读取资源文件,加载驱动
try{
config.load(JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties")); //静态代码块,读取配置文件
Class.forName(config.getProperty("driver")); //加载驱动
}catch(Exception e){
throw new ExceptionInInitializerError(e);
}
}
public static Connection getConnection() throws SQLException{ //创建链接
return DriverManager.getConnection(config.getProperty("url"),config.getProperty("username"),config.getProperty("password"));
}
public static void release(Connection conn,Statement st,ResultSet rs){ //释放资源
if(rs != null){
try{
rs.close();
}catch(Exception e){}
}
if(st != null){
try{
st.close();
}catch(Exception e){}
}
if(conn != null){
try{
conn.close();
}catch(Exception e){}
}
}
}
test.java
public User find(String id){
Connectionconn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection(); //创建链接,引用JdbcUtils工具包
String sql = ""; //其余步骤省略
}catch(Exception e){
throws new DaoException(e);
}finally{
Jdbcutils.release(conn,st,rs); //释放资源
}
}
该类中用到了c3p0数据源和ThreadLocal类,也涉及到了mysql的事物开启与提交。ThreadLocal的作用:set(Object obj)将一个对象 “存入” 到当前线程, Object get()方法将一个对象从当前线程中将对象取出来,所以我们可以将从c3p0中得到的数据库链接存入当前的线程中,也可以将数据库链接从当前线程中取出来
代码如下
c3p0-config.xml
<c3p0-config>
<!-- c3p0-config.xml的默认配置,在classpath下-->
<!-- 如果要使用自己的配置,需要该name属性 -->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
<property name="user">root</property>
<property name="password">mysqladmin</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">20</property>
<property name="minPoolSize">5</property>
<property name="maxStatements">200</property>
</default-config>
<!-- 自己的配置 -->
<named-config name="mysql">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
<property name="user">root</property>
<property name="password">mysqladmin</property>
<property name="acquireIncrement">50</property>
<property name="initialPoolSize">100</property>
<property name="minPoolSize">50</property>
<property name="maxPoolSize">1000</property><!-- intergalactoApp adopts a different approach to configuring statement caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property>
</named-config>
<named-config name="oracle">
<property name="acquireIncrement">50</property>
<property name="initialPoolSize">100</property>
<property name="minPoolSize">50</property>
<property name="maxPoolSize">1000</property><!-- intergalactoApp adopts a different approach to configuring statement caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
JdbcUtils.java
public class DbUtils {
private static ComboPooledDataSource ds = null; //c3p0数据源
/*
用于存放当前线程的connection
所以在当前线程下,无论在哪或的的connection都是同一个connection
在事物上安全
*/
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
static{
try{
ds = new ComboPooledDataSource(); //创建数据源
}catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public static ComboPooledDataSource getDataSource(){ //获得数据源
return ds;
}
public static Connection getConnection() throws SQLException{ //获得数据库链接
try{
Connection conn = tl.get(); //从当前线程获取链接,是同一个connection,所以线程安全
if(conn == null){
conn = ds.getConnection(); //从连接池获得链接
tl.set(conn); //当前线程,所以线程安全
}
return conn;
}catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void startTransaction(){ //开启事物
try{
Connection conn = tl.get(); //从当前线程获取链接,所以线程安全
if(conn == null){
conn = ds.getConnection();
tl.set(conn);
}
conn.setAutoCommit(false);
}catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void commitTransaction(){ //提交事物
try{
Connection conn = tl.get(); //从当前线程获取链接,所以线程安全
if(conn != null){
conn.commit();
}
}catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void closeConnection(){ //关闭链接
try{
Connection conn = tl.get();
if(conn != null){
conn.close();
}
}catch (Exception e) {
// TODO: handle exception
}finally{
tl.remove();//千万注意,解除当前线程上绑定的链接(从threadlocal容器中移除对应当前线程的链接)
}
}
public static void release(Connection conn,PreparedStatement ps,ResultSet rs){ //释放资源
if(rs != null){
try{
rs.close();
}catch (Exception e) {
// TODO: handle exception
}
}
if(ps != null){
try{
ps.close();
}catch (Exception e) {
// TODO: handle exception
}
}
if(conn != null){
try{
conn.close();
}catch (Exception e) {
// TODO: handle exception
}
}
}
}
test.java
@Test
//转账测试,多条sql语句在同一个connection下执行
public void transfer() throws SQLException{
Connection conn = null;
conn = DbUtils.getConnection(); //从当前线程得到Connection
conn.setAutoCommit(false); //开启事物
QueryRunner qr = new QueryRunner();
String sql1 = "update account set money=money-100 where name='aaa'";
qr.update(conn, sql1); //会回滚
// int i = 1/0; //抛异常
String sql2 = "update account set money=money+100 where name='bbb'";
qr.update(conn, sql2);
conn.commit(); //提交事物
}
更多推荐
已为社区贡献4条内容
所有评论(0)