使用端引入自定义持久层框架jar包,定义自定义持久层框架本身就是对JDBC代码进行封装,去解决或者规避原生JDBC在使用中的一些问题。
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.17version>
dependency>
<dependency>
<groupId>c3p0groupId>
<artifactId>c3p0artifactId>
<version>0.9.1.2version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.12version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.10version>
dependency>
<dependency>
<groupId>dom4jgroupId>
<artifactId>dom4jartifactId>
<version>1.6.1version>
dependency>
<dependency>
<groupId>jaxengroupId>
<artifactId>jaxenartifactId>
<version>1.1.6version>
dependency>
dependencies>
<configuration>
<dataSource>
<property name="driverClass" value="com.mysql.jdbc.Driver">property>
<property name="jdbcUrl" value="jdbc:mysql:///localbase1">property>
<property name="user" value="root">property>
<property name="password" value="0000">property>
dataSource>
<mapper resource="usermapper.xml">mapper>
configuration>`
<mapper namespace="com.lagou.dao.IUserDao">
<select id="findAll" resultType="com.lagou.pojo.User" >
select * from user
select>
<select id="findByCondition" resultType="com.lagou.pojo.User" paramterType="com.lagou.pojo.User">
select * from user where id = #{id} and username = #{username}
select>
<insert id="addUser" paramterType="com.lagou.pojo.User">
insert into user values (#{id},#{username},#{password},#{birthday})
insert>
<update id="updateUser" paramterType="com.lagou.pojo.User">
update user set username = #{username} ,password = #{password}, birthday = #{birthday}
where id = #{id}
update>
<delete id="deleteUser" paramterType="java.lang.Integer">
delete from user where id = #{id}
delete>
mapper>
public class Resources {
//根据配置文件的路径,将配置文件加载成字节流
public static InputStream getResourceAsStream(String path){
InputStream resourceAsStream = Resources.class.getClassLoader().getResourceAsStream(path);
return resourceAsStream;
}
}
存放sqlMapConfig.xml解析出来的内容,具体如下
public class Configuration {
private DataSource dataSource;
/*
* key:statementId
* value:mappedStatement对象
* */
Map<String,MappedStatement> mappedStatementMap = new HashMap<>();
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public Map<String, MappedStatement> getMappedStatementMap() {
return mappedStatementMap;
}
public void setMappedStatementMap(Map<String, MappedStatement> mappedStatementMap) {
this.mappedStatementMap = mappedStatementMap;
}
}
存放mapper.xml解析出来的内容
public class MappedStatement {
//id标识
private String id;
//返回值类型
private String resultType;
//参数值类型
private String paramterType;
//sql语句
private String sql;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getParamterType() {
return paramterType;
}
public void setParamterType(String paramterType) {
this.paramterType = paramterType;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
}
创建SqlSessionFactoryBuilder类以及build(InputStream in)
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(InputStream in) throws PropertyVetoException, DocumentException {
//使用dom4j解析配置文件,将解析出来的内容封装到Configuration中
XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder();
Configuration configuration = xmlConfigBuilder.parseConfig(in);
//创建SqlSessionFactory对象
DefaultSqlSessionFactory defaultSqlSessionFactory = new DefaultSqlSessionFactory(configuration);
return defaultSqlSessionFactory;
}
}
public class XMLConfigBuilder {
private Configuration configuration;
public XMLConfigBuilder() {
this.configuration = new Configuration();
}
/**使用dom4j将配置文件解析封装Configuration的方法
*
* @param inputStream
* @return
*/
public Configuration parseConfig(InputStream inputStream) throws DocumentException, PropertyVetoException {
Document document = new SAXReader().read(inputStream);
//
Element rootElement = document.getRootElement();
List<Element> list = rootElement.selectNodes("//property");
Properties properties = new Properties();
for (Element element : list) {
String name = element.attributeValue("name");
String value = element.attributeValue("value");
properties.setProperty(name,value);
}
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
comboPooledDataSource.setUser(properties.getProperty("user"));
comboPooledDataSource.setPassword(properties.getProperty("password"));
configuration.setDataSource(comboPooledDataSource);
//mapper.xml解析:拿到路径--字节输入流--dom4j进行解析
List<Element> mapperlist = rootElement.selectNodes("//mapper");
for (Element element : mapperlist) {
String mapperPath = element.attributeValue("resource");
InputStream resourceAsStream = Resources.getResourceAsStream(mapperPath);
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);
xmlMapperBuilder.parse(resourceAsStream);
}
return configuration;
}
}
public class XMLMapperBuilder {
private Configuration configuration;
public XMLMapperBuilder(Configuration configuration) {
this.configuration = configuration;
}
public void parse(InputStream in) throws DocumentException {
Document document = new SAXReader().read(in);
Element rootElement = document.getRootElement();
String namespace = rootElement.attributeValue("namespace");
List<Element> list = rootElement.selectNodes("//select|//delete|//update|//insert");
for (Element element : list) {
String id = element.attributeValue("id");
String resultType = element.attributeValue("resultType");
String paramterType = element.attributeValue("paramterType");
String sqlTest = element.getTextTrim();
MappedStatement mappedStatement = new MappedStatement();
mappedStatement.setId(id);
mappedStatement.setResultType(resultType);
mappedStatement.setParamterType(paramterType);
mappedStatement.setSql(sqlTest);
String key = namespace+"."+id;
configuration.getMappedStatementMap().put(key,mappedStatement);
}
}
}
通过openSession()方法生产SqlSession
public interface SqlSessionFactory {
public SqlSession openSession();
}
public class DefaultSqlSessionFactory implements SqlSessionFactory{
private Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
@Override
public SqlSession openSession() {
return new DefaultSqlSession(configuration);
}
}
定义对数据库的Crud操作,以及代理方法getMapper()
public interface SqlSession {
//查询所有
public <E> List<E> selectList(String statementid, Object... params) throws Exception;
//查询单个
public <T> T selectOne(String statementid, Object... params) throws Exception;
//为DAO接口生成代理实现类
public <T> T getMapper(Class<?> mapperClass);
public Boolean except(String statementId, Object[] args) throws Exception;
}
public class DefaultSqlSession implements SqlSession {
private Configuration configuration;
public DefaultSqlSession(Configuration configuration) {
this.configuration = configuration;
}
@Override
public <E> List<E> selectList(String statementid,Object... params) throws Exception {
//完成对simpleExecutor里的query方法的调用
SimpleExecutor simpleExecutor = new SimpleExecutor();
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementid);
List<Object> list = simpleExecutor.query(configuration, mappedStatement, params);
return (List<E>) list;
}
@Override
public <T> T selectOne(String statementid, Object... params) throws Exception {
List<Object> objects = selectList(statementid,params);
if(objects.size()==1){
return (T) objects.get(0);
}else{
throw new RuntimeException("查询结果为空或者返回结果过多");
}
}
@Override
public <T> T getMapper(Class<?> mapperClass) {
//使用JDK动态代理为DAO接口生成代理实现类
Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{
mapperClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取方法名
String methodName = method.getName();
String className = method.getDeclaringClass().getName();
//获取statementId
String statementId = className+"."+methodName;
Type genericReturnType = method.getGenericReturnType();
Class<?> returnType = method.getReturnType();
if(returnType == List.class){
System.out.println("返回类型为:list");
}
//判断是否为增删改方法
if(methodName.contains("delete")||methodName.contains("update")||methodName.contains("insert")||methodName.contains("add")){
return except(statementId,args);
}
//泛型类型参数化
if(genericReturnType instanceof ParameterizedType){
List<Object> objects = selectList(statementId, args);
return objects;
}
return selectOne(statementId,args);
}
});
return (T) proxyInstance;
}
@Override
public Boolean except(String statementId, Object[] args) throws Exception {
//将要去完成对simpleExecutor里的executeUpdate方法的调用
SimpleExecutor simpleExecutor = new SimpleExecutor();
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
return simpleExecutor.except(configuration, mappedStatement, args);
}
}
public interface Executor {
public <E> List<E>
query(Configuration configuration, MappedStatement mappedStatement,Object... params) throws SQLException, Exception;
public boolean except(Configuration configuration,MappedStatement mappedStatement,Object... params)throws Exception;
}
public class SimpleExecutor implements Executor {
@Override
public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
//1.注册驱动,获取链接
Connection connection = configuration.getDataSource().getConnection();
//2.获取sql语句,转换sql语句,转换的过程中还需要对#{}中的值进行解析存储
String sql = mappedStatement.getSql();
BoundSql boundSql = getBoundSql(sql);
//3.获取预处理对象
PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
//4.设置参数
List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
String paramterType = mappedStatement.getParamterType();
Class<?> parameterTypeClass = getClassType(paramterType);
for (int i = 0; i < parameterMappingList.size(); i++) {
ParameterMapping parameterMapping = parameterMappingList.get(i);
String content = parameterMapping.getContent();
//反射
Field declaredField = parameterTypeClass.getDeclaredField(content);
//暴力访问
declaredField.setAccessible(true);
Object o = declaredField.get(params[0]);
preparedStatement.setObject(i+1,o);
}
//5.执行SQL
ResultSet resultSet = preparedStatement.executeQuery();
String resultType = mappedStatement.getResultType();
Class<?> resultTypeClass = getClassType(resultType);
// = resultTypeClass.newInstance();
ArrayList<Object> results = new ArrayList<>();
//6.封装返回结果集
while(resultSet.next()){
Object o1 = resultTypeClass.newInstance();
//去除resultSet中的元数据 ResultSetMetaData元数据
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
//字段名
String columnName = metaData.getColumnName(i);
//字段值
Object value = resultSet.getObject(columnName);
//使用反射或者内省根据数据库表和实体的对应关系,完成封装,PropertyDescriptor类是内省库中的类
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
Method readMethod = propertyDescriptor.getWriteMethod();
readMethod.invoke(o1,value);
}
results.add(o1);
}
return (List<E>) results;
//return new ArrayList<>();
}
/**增删改
*
* @param configuration
* @param mappedStatement
* @param params
* @return
* @throws Exception
*/
@Override
public boolean except(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
//1.注册驱动,获取链接
Connection connection = configuration.getDataSource().getConnection();
//2.获取sql语句,转换sql语句,转换的过程中还需要对#{}中的值进行解析存储
String sql = mappedStatement.getSql();
BoundSql boundSql = getBoundSql(sql);
//3.获取预处理对象
PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
//获取参数类型
String parameterType = mappedStatement.getParamterType();
Class<?> paramClassType = getClassType(parameterType);
List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
if (parameterMappingList.size()==1){
preparedStatement.setObject(1,params[0]);
}else{
for (int i = 0; i < parameterMappingList.size(); i++) {
ParameterMapping parameterMapping = parameterMappingList.get(i);
String content = parameterMapping.getContent();
Field declaredField = paramClassType.getDeclaredField(content);
declaredField.setAccessible(true);
Object o = declaredField.get(params[0]);
preparedStatement.setObject(i+1,o);
}
}
return preparedStatement.executeUpdate()>0;
}
private Class<?> getClassType(String paramterType) throws ClassNotFoundException {
if(paramterType!=null){
Class<?> aClass = Class.forName(paramterType);
return aClass;
}
return null;
}
/**完成对#{}的解析工作 1.将#{}使用?代替 2.解析出#{}里边的值进行存储
*
* @param sql
* @return
*/
private BoundSql getBoundSql(String sql) {
//标记处理类:配置标记解析器来完成对占位符的解析处理工作
ParameterMappingTokenHandler tokenHandler = new ParameterMappingTokenHandler();
//标记解析器
GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", tokenHandler);
//解析出来的SQL
String genericsql = genericTokenParser.parse(sql);
//解析出来的参数名称
List<ParameterMapping> parameterMappings = tokenHandler.getParameterMappings();
BoundSql boundSql = new BoundSql(genericsql,parameterMappings);
return boundSql;
}
}