(代码已上传,在文章顶部mybatis-salulu.zip文件)
一,mybaits的单独使用:
看mybatis官网文档,入门篇:
官网地址:https://mybatis.org/mybatis-3/zh/getting-started.html
步骤:
1,读取配置文件
2,构建sqlSession工厂
3,打开sqlSession工厂
4,获取mapper对象
5,使用mapper对象执行数据库操作
二,手写实现:
1,新建一个maven项目,pom.xml中引入mysql的数据库驱动即可
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
</dependencies>
2,准备工作:测试用的表、测试类、实体类、Mapper和Mapper映射;
2.1 mysql数据库中新建一个user表,用于测试使用:
create table user
(
id int auto_increment
primary key,
name varchar(32) null,
age int default 17 null,
email varchar(64) null
);
表中随便写几条数据:
2.2 使用mybatis-generator-maven-plugin帮我们生成实体类、Mapper和Mapper映射;
User实体类:(省略get,set方法)
package com.salulu.test.entity;
public class User {
private Integer id;
private String name;
private Integer age;
private String email;
}
User的Mapper:
(对应非实体类参数,都使用了@Param注解)
package com.salulu.test.mapper;
import com.salulu.baits.annotations.Param;
import com.salulu.test.entity.User;
import java.util.List;
public interface UserMapper {
int deleteByPrimaryKey(@Param("id") Integer id);
int insert(User record);
User selectByPrimaryKey(@Param("id") Integer id);
List<User> selectByNameAndAge(@Param("name") String name,@Param("age") int age);
List<User> selectByName(@Param("name") String name);
List<User> selectAll();
int updateByPrimaryKey(User record);
}
UserMapper的xml映射文件:
(做了一点修改:动态sql语句删除了,resultMap也没有使用,而是使用*来替代,因为解析起来比较麻烦)
<?xml version="1.0" encoding="UTF-8" ?>
<!--<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >-->
<mapper namespace="com.salulu.test.mapper.UserMapper" >
<resultMap id="BaseResultMap" type="com.salulu.test.entity.User" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="age" property="age" jdbcType="INTEGER" />
<result column="email" property="email" jdbcType="VARCHAR" />
</resultMap>
<sql id="Base_Column_List" >
id, name, age, email
</sql>
<select id="selectByPrimaryKey" resultType="com.salulu.test.entity.User" parameterType="java.lang.Integer" >
select *
from user
where id = #{id,jdbcType=INTEGER}
</select>
<select id="selectAll" >
select *
from user
</select>
<select id="selectByNameAndAge" resultType="com.salulu.test.entity.User">
select *
from user
where name = #{name,jdbcType=VARCHAR} and age = #{age,jdbcType=INTEGER}
</select>
<select id="selectByName" resultType="com.salulu.test.entity.User">
select *
from user
where name = #{name,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from user
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.salulu.test.entity.User" >
insert into user (id, name, age,
email)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER},
#{email,jdbcType=VARCHAR})
</insert>
<update id="updateByPrimaryKey" parameterType="com.salulu.test.entity.User" >
update user
set name = #{name,jdbcType=VARCHAR},
age = #{age,jdbcType=INTEGER},
email = #{email,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
</update>
</mapper>
2.3 mybatis-config.xml配置文件:
(DTD校验注释了)
<?xml version="1.0" encoding="UTF-8" ?>
<!--<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">-->
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true"/>
<property name="username" value="root"/>
<property name="password" value="xiaobai"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
文件结构如下:
3,实现如下功能:
读取配置文件
构建sqlSession工厂
打开sqlSession工厂
获取mapper对象
使用mapper对象执行数据库操作
3.新建一个包,用来存放自己实现mybatis的代码
com.salulu.batis
3.1 读取配置文件
新建一个类 Resources
package com.salulu.baits.io;
import java.io.InputStream;
public class Resources {
// 传入资源路径,将资源读入到流中
public static InputStream getResourceAsStream(String resource){
InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
return resourceAsStream;
}
}
使用:
public static void main(String[] args) {
// 1,读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
}
3.2 构建sqlSession工厂
新建一个SqlSessionFactoryBuilder类
package com.salulu.baits.session;
import com.salulu.baits.config.Configuration;
import com.salulu.baits.parse.XMLConfigBuilder;
import java.io.InputStream;
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(InputStream inputStream){
// 1,解析xml配置文件,得到配置封装Configuration对象
Configuration configuration = new XMLConfigBuilder(inputStream).parse();
//2, 根据配置文件构建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactory(configuration);
return sqlSessionFactory;
}
}
3.2.1 解析xml配置文件,得到配置封装Configuration对象
package com.salulu.baits.parse;
import com.salulu.baits.config.Configuration;
import com.salulu.baits.config.Environment;
import com.salulu.baits.config.MappedStatement;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
public class XMLConfigBuilder {
private XPathParser xPathParser;
public XMLConfigBuilder(InputStream inputStream) {
this.xPathParser = new XPathParser(inputStream);
}
/**
* 解析xml文档,把解析出来的数据封装到Configuration对象中
* @return
*/
public Configuration parse() {
// xpath表达式解析xml
Node dataSourceNode = xPathParser.xNode("/configuration/environments/environment/dataSource");
// 数据源属性配置信息
Properties properties = new Properties();
NodeList propertyNodeList = dataSourceNode.getChildNodes();
for(int i=0;i<propertyNodeList.getLength();i++){
Node item = propertyNodeList.item(i);
if(item.getNodeType() == Node.ELEMENT_NODE){
properties.setProperty(item.getAttributes().getNamedItem("name").getNodeValue(),
item.getAttributes().getNamedItem("value").getNodeValue());
}
}
// Mapper映射文件配置信息
Map<String, MappedStatement> mappedStatementMap = new ConcurrentHashMap<>();
Node mapperNodes = xPathParser.xNode("/configuration/mappers");
NodeList mapperNodeList = mapperNodes.getChildNodes();
for(int i =0;i<mapperNodeList.getLength();i++){
Node item = mapperNodeList.item(i);
if(item.getNodeType() == Node.ELEMENT_NODE){
// mapper.xml文件位置
String resource = item.getAttributes().getNamedItem("resource").getNodeValue();
// 解析该mapper.xml文件
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resource);
this.xPathParser = new XPathParser(inputStream);
Element element = xPathParser.getDocument().getDocumentElement();
String namespace = element.getAttribute("namespace");
NodeList sqlNodeList = element.getChildNodes();
for (int j = 0; j < sqlNodeList.getLength(); j++) {
Node sqlNode = sqlNodeList.item(j);
if(sqlNode.getNodeType() == Node.ELEMENT_NODE){
String id = "";
String resultType = "";
String parameterType = "";
Node idNode = sqlNode.getAttributes().getNamedItem("id");
if(null == idNode) throw new RuntimeException("sql id is null");
else id = sqlNode.getAttributes().getNamedItem("id").getNodeValue();
Node resultTypeNode = sqlNode.getAttributes().getNamedItem("resultType");
if(null != resultTypeNode) resultType = sqlNode.getAttributes().getNamedItem("resultType").getNodeValue();
Node parameterTypeNode = sqlNode.getAttributes().getNamedItem("parameterType");
if(null != parameterTypeNode) parameterType = sqlNode.getAttributes().getNamedItem("parameterType").getNodeValue();
String sql = sqlNode.getTextContent();
sql = sql.replaceAll("[\r\n| ]+"," ");
MappedStatement mappedStatement = new MappedStatement();
mappedStatement.setId(id);
mappedStatement.setNamespace(namespace);
mappedStatement.setParameterType(parameterType);
mappedStatement.setResultType(resultType);
mappedStatement.setSql(sql);
mappedStatementMap.put(namespace+"."+id,mappedStatement);
}
}
}
}
// 将解析出来的值封装到Configuration
Configuration configuration = new Configuration();
Environment environment = new Environment();
environment.setDriver(properties.getProperty("driver"));
environment.setPassword(properties.getProperty("password"));
environment.setUsername(properties.getProperty("username"));
environment.setUrl(properties.getProperty("url"));
configuration.setEnvironment(environment);
configuration.setMappedStatementMap(mappedStatementMap);
return configuration;
}
}
XPathParser对象:
package com.salulu.baits.parse;
import com.salulu.baits.exception.BuilderException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.InputStream;
public class XPathParser {
private XPath xPath;
private Document document;
public XPathParser(InputStream inputStream) {
this.xPath = createXPath();
this.document = createDocument(new InputSource(inputStream));
}
// 初始化XPath
public XPath createXPath(){
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
return xPath;
}
private Document createDocument(InputSource inputSource){
try {
// JDK 提供的文档解析工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);// 设置是否支持命名空间
factory.setIgnoringComments(true);// 设置是否忽略注释
factory.setIgnoringElementContentWhitespace(false);// 设置是否忽略元素内容空白
factory.setCoalescing(false);// 是否将CDATA节点转换为文本节点
factory.setExpandEntityReferences(true);// 设置是否展开实体引用节点,这里是sql片段引用
factory.setValidating(false);
DocumentBuilder builder = factory.newDocumentBuilder();// 创建一个documentBuilder对象
builder.setErrorHandler(new ErrorHandler() {
@Override
public void warning(SAXParseException e) throws SAXException {
throw e;
}
@Override
public void error(SAXParseException e) throws SAXException {
throw e;
}
@Override
public void fatalError(SAXParseException e) throws SAXException {
throw e;
}
});
Document parse = builder.parse(inputSource);
return parse;
} catch (Exception e) {
throw new BuilderException("创建document发生错误. cause:"+e,e);
}
}
// 根据一个xpath表达式解析一个xml节点
public Node xNode(String expression){
Node node = null;
try {
node = (Node) xPath.evaluate(expression,document, XPathConstants.NODE);
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return node;
}
public XPath getxPath() {
return xPath;
}
public void setxPath(XPath xPath) {
this.xPath = xPath;
}
public Document getDocument() {
return document;
}
public void setDocument(Document document) {
this.document = document;
}
}
3.2.2 根据配置文件构建sqlSessionFactory
创建一个SqlSessionFactory类,传入配置信息(主要是需要读取到数据库连接配置)
package com.salulu.baits.session;
import com.salulu.baits.config.Configuration;
import com.salulu.baits.executor.Executor;
public class SqlSessionFactory {
// 传入的配置信息
private Configuration configuration;
public SqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
public SqlSession openSession() {
// 创建一个执行器
Executor executor = new Executor(configuration);
// 创建一个SqlSession对象,并传入执行器用来执行sql
SqlSession session = new SqlSession(configuration, executor);
return session;
}
}
3.2.2.1 创建一个执行器Executor类
package com.salulu.baits.executor;
import com.salulu.baits.config.Configuration;
import com.salulu.baits.config.MappedStatement;
import com.salulu.baits.datasource.PooledDataSource;
import com.salulu.baits.reflection.Reflection;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 执行器
*/
public class Executor {
private Configuration configuration;
private PooledDataSource pooledDataSource;
public Executor(Configuration configuration) {
this.configuration = configuration;
// 初始化数据源,创建一个连接池
pooledDataSource = new PooledDataSource(configuration.getEnvironment());
}
/**
* 传入sql和参数执行sql语句并返回结果
* @param mappedStatement
* @param parameterMap
* @return
*/
public Object execute(MappedStatement mappedStatement, Map<String,Object> parameterMap){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
Object res = null;
String sql = mappedStatement.getSql();
sql = sql.trim();
List<String> keyList = repSql(sql);
sql = keyList.get(keyList.size()-1);//取出处理好的sql语句
keyList.remove(keyList.size()-1);//将sql语句从list集合中删除
System.out.println("sql:"+sql+", param:"+parameterMap);// 输出sql语句和参数
try {
connection = pooledDataSource.getConnection();
preparedStatement = connection.prepareStatement(sql);// 预编译sql
// 设置参数,根据key设置对应的参数
for (int i = 0; i < keyList.size(); i++) {
String key = keyList.get(i);
Object value = parameterMap.get(key);
if(value instanceof Integer){
preparedStatement.setInt(i+1,(Integer)value);
}else if(value instanceof String){
preparedStatement.setString(i+1,value.toString());
}else if(value instanceof Boolean){
preparedStatement.setBoolean(i+1,(Boolean)value);
}
}
// 执行sql语句
if(sql.startsWith("select") || sql.startsWith("SELECT")){//查询使用executeQuery()方法
resultSet = preparedStatement.executeQuery();
// 处理结果,把resustSet的结果集映射到java对象
res = mappingResultSet(resultSet, mappedStatement.getResultType());
}else {// 增删改使用executeUpdate()方法
res = preparedStatement.executeUpdate();
}
return res;
}catch (Exception e){
e.printStackTrace();
}finally {
// 关闭 resultSet,preparedStatement,connection
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* 从mapper配置文件中读取到的sql语句需要处理,#{id,jdbcType=INTEGER}这种表达式jdbctemplate是无法解析的
* 需要把表达式替换为?占位符
* @param sql
* @return
*/
public List<String> repSql(String sql) {
List<String> keyList = new ArrayList<>();
while (true){
int a = sql.indexOf("#{");
if(a == -1) break;
int b = sql.indexOf("}");
String paramE = sql.substring(a, b + 1).replace(" ","");
sql = sql.replace(paramE, "?");// 将#{}替换为?占位符
int c = paramE.indexOf(",");
String key = paramE.substring(2, c);
keyList.add(key);
}
keyList.add(sql);// 将替换为占位符的sql语句放到集合中
return keyList;
}
// 封装结果集
public Object mappingResultSet(ResultSet resultSet,String resultType){
// 查询结果可能是一个或者多个,这里使用list来存放结果
List resList = new ArrayList();
try{
Class<?> clazz = Class.forName(resultType);
if(resultSet.next()){
// 根据返回类型,使用反射来生成一个对象
Object entity = clazz.newInstance();
// 为新生成的对象的属性赋值
Reflection.setPropertiesToBeanFromResultSet(entity,resultSet);
resList.add(entity);
}
} catch (Exception e) {
e.printStackTrace();
}
return resList;
}
}
3.2.2.1.1 实现一个连接池
package com.salulu.baits.datasource;
import com.salulu.baits.config.Environment;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
public class PooledDataSource {
private final LinkedList<Connection> pool =new LinkedList<>();
private int minSize = 5;
private Environment environment;
public PooledDataSource(Environment environment) {
this.environment = environment;
initPool();
}
private void initPool(){
try {
Class.forName(environment.getDriver());
for (int i = 0; i < minSize; i++) {// 这里创建一个固定大小的连接池
Connection conn = DriverManager.getConnection(environment.getUrl(), environment.getUsername(), environment.getPassword());
Connection connProxy = (Connection)Proxy.newProxyInstance(this.getClass().getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object obj, Method method, Object[] objects) throws Throwable {
// 对连接对象的close()方法进行覆盖,不要真的关闭连接,而是把连接放回池中
if(method.getName().equals("close")){
pool.addLast(conn);
return null;
}else {
return method.invoke(conn,objects);
}
}
});
pool.add(connProxy);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
// 从池中获取一个连接对象
public Connection getConnection(){
Connection result =null;
synchronized (pool) {
if(pool.size()>0){
result = pool.removeFirst();
}
}
return result;
}
}
3.2.2.1.2 为新生成的对象的属性赋值这个过程:新建一个类(Reflection),封装成一个方法
package com.salulu.baits.reflection;
import java.lang.reflect.Field;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
public class Reflection {
public static void setPropertiesToBeanFromResultSet(Object entity, ResultSet resultSet){
// 根据结果集,获取到数据库表的元数据信息,这个信息里有详细的表的列,字段信息
try {
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
// 字段个数
int columnCount = resultSetMetaData.getColumnCount();
// 获取到对象所声明的成员变量
Field[] fieldArray = entity.getClass().getDeclaredFields();
for (int i=0;i<columnCount;i++) {
String columnName = resultSetMetaData.getColumnName(i + 1);
columnName = columnName.replace("_", "");
for (int j = 0; j < fieldArray.length; j++) {
// 对象中的成员变量
Field field = fieldArray[j];
field.setAccessible(true);
String name = field.getName();
if(name.equals(columnName)){
String fieldTypeName = field.getType().getSimpleName();
if(fieldTypeName.equals("Integer")){
int columnValue = resultSet.getInt(columnName);
field.set(entity,columnValue);
}else if(fieldTypeName.equals("Long")){
long columnValue = resultSet.getLong(columnName);
field.set(entity,columnValue);
}else if(fieldTypeName.equals("Float")){
float columnValue = resultSet.getFloat(columnName);
field.set(entity,columnValue);
}else if(fieldTypeName.equals("Double")){
double columnValue = resultSet.getDouble(columnName);
field.set(entity,columnValue);
}else if(fieldTypeName.equals("String")){
String columnValue = resultSet.getString(columnName);
field.set(entity,columnValue);
}else if(fieldTypeName.equals("Date")){
Date columnValue = resultSet.getDate(columnName);
field.set(entity,columnValue);
}else if(fieldTypeName.equals("Boolean")){
boolean columnValue = resultSet.getBoolean(columnName);
field.set(entity,columnValue);
}else{
Object object = resultSet.getObject(columnName);
System.out.println("实体类中的字段类型为非基本类型,获取到的值为:"+object.toString());
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2.2.2 创建一个SqlSession对象,并传入执行器用来执行sql
package com.salulu.baits.session;
import com.salulu.baits.config.Configuration;
import com.salulu.baits.config.MappedStatement;
import com.salulu.baits.executor.Executor;
import com.salulu.baits.proxy.MapperProxy;
import java.lang.reflect.Proxy;
import java.util.Map;
public class SqlSession {
private Configuration configuration;
private Executor executor;
/**
* 传入配置信息(可以从配置信息中获取sql语句)
* 传入执行器,用来执行sql
* @param configuration
* @param executor
*/
public SqlSession(Configuration configuration, Executor executor) {
this.configuration = configuration;
this.executor = executor;
}
/**
* 获取mapper的方法,因为mapper是一个接口,这里使用反射,为mapper接口生成一个实现类返回
* @param interfaceClass
* @param <T>
* @return
*/
public <T> T getMapper(Class<T> interfaceClass) {
MapperProxy mapperProxy = new MapperProxy(this);
T t = (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),
new Class[]{interfaceClass},
mapperProxy);
return t;
}
public Object execute(String sqlId, Map<String,Object> parameterMap){
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(sqlId);
Object res = executor.execute(mappedStatement, parameterMap);
return res;
}
}
3.2.2.2.1 使用反射,为mapper接口生成一个实现类 的代码实现:
新建一个MapperProxy类,实现InvocationHandler接口:
package com.salulu.baits.proxy;
import com.salulu.baits.annotations.Param;
import com.salulu.baits.session.SqlSession;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MapperProxy implements InvocationHandler {
private SqlSession sqlSession;
public MapperProxy(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
String methodName = method.getName();
String sqlId = method.getDeclaringClass().getName()+"."+ methodName;
Map<String,Object> parameterMap = null;
// 处理一个或多个非User类型参数
// 从@Param注解中获取参数与sql配置文件中的对应关系(强制要求使用@Param来标示参数对应的是那个字段)
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
if(parameterAnnotations!=null && parameterAnnotations.length>0
&& parameterAnnotations[0]!=null && parameterAnnotations[0].length>0){
parameterMap = new HashMap<>();
for(int i =0;i<parameterAnnotations.length;i++){
Annotation[] parameterAnnotation = parameterAnnotations[i];
Param param = (Param) parameterAnnotation[0];
parameterMap.put(param.value(),objects[i]);
}
}else{
// 处理新增方法的实体类类型的参数,比如User类
// 将User类的数据信息封装为一个Map
parameterMap = new HashMap<>();
Object entity = objects[0];
Field[] fields = entity.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String name = field.getName();
Object value = field.get(entity);
parameterMap.put(name,value);
}
}
Object object = sqlSession.execute(sqlId, parameterMap);
Class<?> returnType = method.getReturnType();
String returnTypeSimpleName = returnType.getSimpleName();
// 返回类型returnTypeSimpleName,一般为list,实体类对象,还有int型
// 由于执行sql的返回结果默认是返回list和int型的,如果使用实体类接受数据的话会发生类型转换异常
// 这里需要特殊处理一下
if( !"List".equals(returnTypeSimpleName) && !(object instanceof Integer)){
// 不是list也不是int,说明返回的是实体类型,比如说User对象,那么可以从list中获取第一个数据(如果存在的话)
if(object!=null){
List list = (List) object;
if(list!=null && list.size()>0){// 如果存在则获取,如果不存在则返回null即可
object = list.get(0);
}
}
}
return object;
}
}
@Param注解类:
package com.salulu.baits.annotations;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface Param {
String value();
}
构建session工厂的使用:
// 1,读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2,构建session工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
3.3 打开sqlsession
SqlSessionFactory类中提供了openSession()方法
上文代码中有写到:
public SqlSession openSession() {
// 创建一个执行器
Executor executor = new Executor(configuration);
// 创建一个SqlSession对象,并传入执行器用来执行sql
SqlSession session = new SqlSession(configuration, executor);
return session;
}
3.4 获取mapper接口对象
SqlSession这个类中有实现这个方法,上文代码中有写到过:
/**
* 获取mapper的方法,因为mapper是一个接口,这里使用反射,为mapper接口生成一个实现类返回
* @param interfaceClass
* @param <T>
* @return
*/
public <T> T getMapper(Class<T> interfaceClass) {
MapperProxy mapperProxy = new MapperProxy(this);
T t = (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),
new Class[]{interfaceClass},
mapperProxy);
return t;
}
3.5 使用获取到的mapper对象执行方法,如selectByPrimaryKey();insert();deleteByPrimaryKey();selectByName();
package com.salulu.test;
import com.salulu.baits.io.Resources;
import com.salulu.baits.session.SqlSession;
import com.salulu.baits.session.SqlSessionFactory;
import com.salulu.baits.session.SqlSessionFactoryBuilder;
import com.salulu.test.entity.User;
import com.salulu.test.mapper.UserMapper;
import java.io.InputStream;
import java.util.List;
public class Test1 {
public static void main(String[] args) {
// 1,读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2,构建session工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3,打开sqlsession
SqlSession session = sqlSessionFactory.openSession();
// 4,获取mapper接口对象
UserMapper userMapper = session.getMapper(UserMapper.class);
// 5,调用mapper对象的方法类执行sql,对数据库进行操作
int i = userMapper.deleteByPrimaryKey(3);
List<User> xiaobaiUserList = userMapper.selectByName("小白");
System.out.println("xiaobaiUserList:"+xiaobaiUserList);
User user2 = userMapper.selectByPrimaryKey(2);
System.out.println("user2:"+user2);
List<User> userList = userMapper.selectByNameAndAge("小萨", 17);
System.out.println("userList:"+userList);
}
}
4,测试结果:
可以看对对于单表操作可以正常进行。
(代码已上传,在文章顶部mybatis-salulu.zip文件)