Spring的JdbcTemplate使用起来比jdbc简便很多,不用自己写很多重复的代码(不用手动关闭连接!).使用jdbcTemplate和c3p0设计一个通用的dao类,方便以后继承.
什么是JDBC?
①JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。而多的这个template,就是模板,是Spring框架为我们提供的.所以JDBCTemplate就是Spring对JDBC的封装,通俗点说就是Spring对jdbc的封装的模板
创建数据库
我使用mysql,创建一个user表做例子
创建user表代码1 2 3 4 5 6 7 8 9 10 11 12 13
| CREATE TABLE `user` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `username` VARCHAR(50) NOT NULL, `password` VARCHAR(50) NOT NULL, `sex` TINYINT(1) NOT NULL, `regDate` DATETIME NULL DEFAULT NULL, `pic` BLOB NULL, `enable` TINYINT(1) NOT NULL, PRIMARY KEY (`id`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB AUTO_INCREMENT=5;
|
引入相应jar包
我使用gradle添加,依赖如下
build.gradle1 2 3 4 5 6 7 8 9 10
| dependencies { testCompile group: 'junit', name: 'junit', version: '4.11' testCompile group: 'junit', name: 'junit', version: '4.12' compile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '9.0.12' compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.12' compile group: 'com.mchange', name: 'c3p0', version: '0.9.5.2' compile group: 'org.springframework', name: 'spring-context', version: '5.0.9.RELEASE' compile group: 'org.springframework', name: 'spring-jdbc', version: '5.0.9.RELEASE' testCompile group: 'org.springframework', name: 'spring-test', version: '5.0.9.RELEASE' }
|
配置applicationContext.xml文件
配置applicationContext.xml文件,配置好c3p0的dataSource,然后再配置jdbcTemplate.到时候要用jdbcTemplate直接找Spring要就可以了,非常方便!
applicationContext.xml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <?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" 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 ">
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mvcdemo"/> <property name="user" value="root"/> <property name="password" value="root"/>
<property name="acquireIncrement" value="3"/> <property name="minPoolSize" value="2"/> <property name="maxPoolSize" value="5"/> <property name="maxStatements" value="5"/> <property name="maxStatementsPerConnection" value="5"/> </bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <context:component-scan base-package="cn.nicenan.mvcdemo.dao.impl"/> </beans>
|
设计User类(bean)
很简单,没啥好说的,遵循javabean规范就可以,字段名要跟数据库中对应表的字段名一致,到时候反射才能生效!(不一样的要在写sql的时候取别名)
User1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| package cn.nicenan.mvcdemo.model;
import java.sql.Blob; import java.sql.Timestamp;
public class User { private int id; private String username; private String password;
public boolean getEnable() { return enable; }
public void setEnable(boolean enable) { this.enable = enable; }
private boolean sex; private boolean enable;
@Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", sex=" + sex + ", regDate=" + regDate + ", pic=" + pic + '}'; }
public boolean getSex() { return sex; }
public void setSex(boolean sex) { this.sex = sex; }
private Timestamp regDate; private Blob pic;
public User() { }
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public Timestamp getRegDate() { return regDate; }
public void setRegDate(Timestamp regDate) { this.regDate = regDate; }
public Blob getPic() { return pic; }
public void setPic(Blob pic) { this.pic = pic; } }
|
设计BaseDao类
想实现一个BaseDao类,给其他Dao类继承,要实现通用,把BaseDao设计成泛型类,等子类继承的时候传入bean的类型,BaseDao类就能通过反射方法,给所有bean设置属性.
首先难点是获取T.class,百度后发现这个方法:
1 2
| private Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
我们设计三个通用的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public int iud(String sql, Object... args) { int rows = getJdbcTemplate().update(sql, args); return rows; }
public T get(String sql, Object... args) { T result = getJdbcTemplate().queryForObject(sql, new UserRowMapper(), args); return result; }
public List<T> getlist(String sql, Object... args) { return getJdbcTemplate().query(sql, args, new UserRowMapper()); }
|
增删改没啥说的,就是调用update方法,传入sql语句参数用?代替,在args传入参数.
JdbcTemplate查询一个(queryForObject)和查询多个对象(query)参数完全一致,主要就是在UserRowMapper这个类的设计,这个类要RowMapper接口,这个接口只有一个mapRow方法,在里面我们可以用反射设计一个通用的方法!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| private class UserRowMapper implements RowMapper<T> {
@Override public T mapRow(ResultSet rs, int rowNum) throws SQLException { try { T entity = entityClass.newInstance(); ResultSetMetaData rsmd = rs.getMetaData(); int count = rsmd.getColumnCount(); for (int i = 0; i < count; i++) { String label = rsmd.getColumnLabel(i + 1); Field field = entityClass.getDeclaredField(label); field.setAccessible(true); field.set(entity, rs.getObject(label)); } return entity;
} catch (InstantiationException | NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } return null; } }
|
这样BaseDao类就设计好了,等等创建UserDao的时候只要调用父类的方法就可以了,非常简单!
UserDao和UserDaoImpl
先在UserDao里设计好接口,UserDaoImpl就继承BaseDao类实现UserDao接口里面的方法就可以了.继承BaseDao的时候泛型要填入User类,这样父类才知道要返回什么类型的数据
代码如下:
UserDao1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package cn.nicenan.mvcdemo.dao;
import cn.nicenan.mvcdemo.model.User;
import java.util.List;
public interface UserDao { int add(User user);
int update(User user);
User get(int id);
User get(String username);
List<User> query(int sex); }
|
UserDaoImpl1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package cn.nicenan.mvcdemo.dao.impl;
import cn.nicenan.mvcdemo.dao.BaseDao; import cn.nicenan.mvcdemo.dao.UserDao; import cn.nicenan.mvcdemo.model.User; import org.springframework.stereotype.Repository;
import java.util.List;
@Repository public class UserDaoImpl extends BaseDao<User> implements UserDao {
@Override public int add(User user) { return super.iud("INSERT INTO user (username,password,sex,regDate,enable)VALUES(?,?,?,?,?)", user.getUsername(), user.getPassword(), user.getSex(), user.getRegDate(), 1); }
@Override public int update(User user) {
return super.iud("UPDATE user SET username = ? , password = ? , sex = ?, regDate = ?, pic = ?, enable = ? where id = ?", user.getUsername(), user.getPassword(), user.getSex(), user.getRegDate(), user.getEnable(), user.getId());
}
@Override public User get(int id) { return super.get("SELECT * FROM user WHERE id=?", id); }
@Override public User get(String username) { return super.get("SELECT * FROM user WHERE username=?", username); }
@Override public List<User> query(int sex) { return super.getlist("SELECT * FROM user WHERE sex=?", sex); }
}
|
编写测试类
test1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import cn.nicenan.mvcdemo.dao.UserDao; import cn.nicenan.mvcdemo.model.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource; import java.sql.Timestamp; import java.util.Date; import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) public class daoTest { @Resource(name = "userDaoImpl") UserDao userDao;
@Test public void ceshi() { User user = new User(); user.setUsername("asd"); user.setPassword("qweas"); user.setSex(false); user.setRegDate(new Timestamp(new Date().getTime())); int rows = userDao.add(user); System.out.println(rows); System.out.println("-------------------------------------------"); List<User> query = userDao.query(1); System.out.println(query);
}
}
|
输出
1 2 3 4
| 1 ------------------------------------------- [User{id=1, username='w', password='q', sex=true, regDate=2018-09-13 20:55:53.0, pic=null}, User{id=2, username='q', password='s', sex=true, regDate=2018-09-14 13:18:08.0, pic=null}]
|
成功!
这样设计其他dao层的时候,直接继承BaseDao,就会变得非常轻松了!