具体配置如下:
public class MybatisTest {
// 入门
public static void main(String[] args) throws Exception {
// 1、 读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2、 创建sqlSessionFactory
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
// 3、 使用工程生产对象
SqlSession session = factory.openSession();
// 5、 使用代理对象执行方法
UserDao userDao = session.getMapper(UserDao.class);
List<User> users = userDao.findAll();
// 6、 释放资源
for (User user : users) {
System.out.println(user.toString());
}
in.close();
}
}
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
这个Resouces是自定义的一个类,用类加载器来读取
public class Resources {
/**
* 根据输入参数,获取一个字节流
* @param filePath
* @return
*/
public static InputStream getResourceAsStream(String filePath) {
return Resources.class.getClassLoader().getResourceAsStream(filePath);
}
}
public interface SqlSessionFactory {
SqlSession openSession();
}
这是一个接口类型的,我们需要一个实现类
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private Configuration cfg;
public DefaultSqlSessionFactory(Configuration cfg) {
this.cfg = cfg;
}
/**
* 用于创建新的数据操作对象
* @return
*/
public SqlSession openSession() {
return new DefaultSqlSession(cfg);
}
}
我们通过SqlSessionFactoryBuilder来创建sqlSessiongFactory
public class SqlSessionFactoryBuilder {
/**
* 根据字节输入流来
* @param in
* @return
*/
public static SqlSessionFactory build(InputStream in) {
Configuration cfg = XMLConfigBuilder.loadConfiguration(in);
return new DefaultSqlSessionFactory(cfg);
}
}
创建工厂时使用到的Configuration,是我们定义的一个类,里面保存着数据连接相关的属性信息
public class Configuration {
// 驱动
private String driver;
// url
private String url;
// username
private String username;
// password
private String password;
// 存储dao中相关操作的信息
private Map<String, Mapper> mappers;
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
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 Map<String, Mapper> getMappers() {
return mappers;
}
public void setMappers(Map<String, Mapper> mappers) {
this.mappers.putAll(mappers);
}
}
XMLConfigBuilder这是一个工具类,用于实现对xml的解析,使用dom4j+xpath方式,也可以通过其他方式,这边就不展示了。
2. 创建好sqlSessionFactory之后,我们就需要创建连接
public interface SqlSession {
/**
* 根据参数创建代理对象
* @param daoInterfaceClass dao接口的字节码
* @param <T>
* @return
*/
<T> T getMapper(Class<T> daoInterfaceClass);
/**
* 释放资源
*/
void close();
}
SqlSession中主要包括两个方法,getMapper是根据参数创建代理对象,close用于释放资源,有一个默认实现类
public class DefaultSqlSession implements SqlSession {
private Configuration cfg;
private Connection connection;
public DefaultSqlSession(Configuration cfg) {
this.cfg = cfg;
connection = DataSourceUtil.getConnection(cfg);
}
public <T> T getMapper(Class<T> daoInterfaceClass) {
return (T) Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(), new Class[]{daoInterfaceClass}, new MapperProxy(cfg.getMappers(), connection));
}
public void close() {
if (connection != null) {
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
里面主要有两个属性,一个是加载的数据库配置信息,还有是Connection属性。
Connection在我们构造的时候通过DataSourceUtil工具类实现
public class DataSourceUtil {
public static Connection getConnection(Configuration cfg) {
try {
Class.forName(cfg.getDriver());
return DriverManager.getConnection(cfg.getUrl(), cfg.getUsername(), cfg.getPassword());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
在SqlSession中创建代理对象进行方法增强时,我们实现的MapperProxy
public class MapperProxy implements InvocationHandler {
// Map的key是全限定类名+方法名
private Map<String, Mapper> mappers;
private Connection conn;
public MapperProxy(Map<String, Mapper> mappers, Connection conn) {
this.mappers = mappers;
this.conn = conn;
}
/**
* 用此方法进行增强,我们的增强就是调用selectList方法
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1、获取方法名
String methodName = method.getName();
// 2、获取方法所在类的名称
String className = method.getDeclaringClass().getName();
// 3、组合key
String key = className + "." + methodName;
// 4、获取mapper中的key的value
Mapper mapper = mappers.get(key);
// 5、是否有mapper
if (mapper == null) {
throw new IllegalArgumentException("传入的参数有误");
}
// 6、调用工具类,查询所有
return new Executor().selectList(mapper, conn);
}
}
Executor是一个工具类,里面封装类selectList方法
public class Executor {
public <E> List<E> selectList(Mapper mapper, Connection conn) {
PreparedStatement pstm = null;
ResultSet rs = null;
try {
// 1、取出mapper中的数据
String queryString = mapper.getQueryString();
String resultType = mapper.getResultType();
Class domainClass = Class.forName(resultType);
// 2、获取PreparedStatement对象
pstm = conn.prepareStatement(queryString);
// 3、执行sql语句,获取结果集
rs = pstm.executeQuery();
// 4、封装结果集
List<E> list = new ArrayList<E>();
while (rs.next()) {
E obj = (E) domainClass.newInstance();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
// 获取每列的列名,序号从1开始
String columnName = rsmd.getColumnName(i);
// 根据列名,获取值
Object columnValue = rs.getObject(columnName);
// 给obj赋值
PropertyDescriptor pd = new PropertyDescriptor(columnName, domainClass);
// 获取写入方法
Method writeMethod = pd.getWriteMethod();
// 赋值对象
writeMethod.invoke(obj, columnValue);
}
list.add(obj);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
release(pstm, rs);
}
return null;
}
private void release(PreparedStatement pstm, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (pstm != null) {
try {
pstm.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
// 5、 使用代理对象执行方法
UserDao userDao = session.getMapper(UserDao.class);
List<User> users = userDao.findAll();
// 6、 释放资源
for (User user : users) {
System.out.println(user.toString());
}
in.close();
原文:https://www.cnblogs.com/liufei-yes/p/12747566.html