Fork me on GitHub

持久层之 MyBatis: 第一篇:快速入门

JDBC回顾

public static void main(String[] args) {
public Connection conn= null;
public PreparedStatement preparedStatement = null;
public ResultSet resultSet = null;
try {
//1.加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//2.通过驱动管理类获取数据库链接
conn=  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "mysql");
//定义sql语句 ?表示占位符
String sql = "select * from user where username = ?";
//获取预处理statement
preparedStatement = conn.prepareStatement(sql);
//设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "韩信");
//向数据库发出sql执行查询,查询出结果集
resultSet =  preparedStatement.executeQuery();
//遍历查询结果集 
while(resultSet.next()){
System.out.println(resultSet.getString("id")+"  "+resultSet.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//释放资源
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
 
}
 
}

JDBC问题总结
代码重复且存在巨大的冗余

jdbc操作步骤总结如下:
1、 加载数据库驱动

2、 创建并获取数据库链接

3、 创建jdbc statement对象

4、 设置sql语句

5、 设置sql语句中的参数(使用preparedStatement)

6、 通过statement执行sql并获取结果

7、 对sql执行结果进行解析处理

1.1.认识MyBatis

在这里插入图片描述
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)

IBATIS是2.0, 到了3.0更名为MyBatis

面试题:MyBatis与Hibernate区别
在这里插入图片描述

1.Hibernate是全自动,而MyBatis是半自动 [简单理解]

Hibernate完全可以通过对象关系模型实现对数据库的操作,
拥有完整的JavaBean对象与数据库的映射结构来自动生成SQL语句。
而MyBatis仅有基本的字段映射,
对象数据以及对象实际关系仍然需要通过定制SQL语句来实现和管理

2.Hibernate数据库移植性远大于MyBatis

Hibernate通过它强大的映射结构和hql语言,
大大降低了对象与数据库(Oracle、MySQL等)的耦合性,
而MyBatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写SQL的方法,
如果SQL不具通用性而用了很多某数据库特性的sql语句的话,
移植性也会随之降低很多,成本很高

3.Hibernate拥有完整的日志系统,MyBatis则欠缺一些。

 Hibernate日志系统非常健全,涉及广泛,
 包括:SQL记录、关系异常、优化警告、缓存提示、脏数据警告等;
 而MyBatis则除了基本记录功能外,功能薄弱很多。

由于MyBatis的sql都是写在xml里,因此优化sql比Hibernate方便很多。
而Hibernate的sql很多都是自动生成的,无法直接维护sql;
虽有hql,但功能还是不及sql强大,见到报表等变态需求时,
hql也歇菜,也就是说hql是有局限的;
hibernate虽然也支持原生sql,但开发模式上却与orm不同,
需要转换思维,因此使用上不是非常方便。
总之写sql的灵活度上Hibernate不及MyBatis

1.1.使用IDEA创建maven工程

直接输入1次#,并按下space后,将生成1级标题。输入2次#,并按下space后,将生成2级标题。以此类推,我们支持6级标题。有助于使用语法后生成一个完美的目录。

在这里插入图片描述
Project name :项目名称
Project location :项目地址
Moudule name :模块名称
在这里插入图片描述
ProjectName:项目名称
Projectlocation:项目路径

1.2.引入mysql依赖包

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.32</version>
</dependency>

在这里插入图片描述

dependency:是依赖的意思 ,dependencies是依赖们的意思加了个S是复数,所以可以放多个依赖

1.3.准备数据

  • 创建数据库
    CREATE DATABASE IF NOT EXISTS mybatis2;

  • 选择数据库
    USE mybatis3;

  • 如果存在就删除
    DROP TABLE IF EXISTS tb_user;

  • 创建表
    CREATE TABLE tb_user (
    id CHAR(32) NOT NULL,
    user_name VARCHAR(32) DEFAULT NULL,
    PASSWORD VARCHAR(32) DEFAULT NULL,
    NAME VARCHAR(32) DEFAULT NULL,
    age INT(10) DEFAULT NULL,
    sex INT(2) DEFAULT NULL,
    birthday DATE DEFAULT NULL,
    created DATETIME DEFAULT NULL,
    updated DATETIME DEFAULT NULL,
    PRIMARY KEY (id)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8;

在这里插入图片描述
**最后一次显示JDBC,这样大家就告别JDBC了,MyBatis的底层也是JDBC大家有兴趣可以用JDBC手写下MyBatis! **

1.4 使用JDBC手写MyBatis框架

本人写的 手写 MyBatis, 无兴趣 可略过:
public final class JDBCUtils {
 
	private static String connect;
	private static String driverClassName;
	private static String URL;
	private static String username;
	private static String password;
	private static boolean autoCommit;
 
	/** 声明一个 Connection类型的静态属性,用来缓存一个已经存在的连接对象 */
	private static Connection conn;
 
	static {
		config();
	}
 
	/**
	 * 开头配置自己的数据库信息
	 */
	private static void config() {
		/*
		 * 获取驱动
		 */
		driverClassName = "com.mysql.jdbc.Driver";
 
		/*
		 * 获取URL
		 */
		URL = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8";
		
        /*
		 * 获取用户名
		 */
		username = "root";
 
		/*
		 * 获取密码
		 */
		password = "mysql";
 
		/*
		 * 设置是否自动提交,一般为false不用改
		 */
		autoCommit = false;
	}
 
	/**
	 * 载入数据库驱动类
	 */
	private static boolean load() {
		try {
			Class.forName(driverClassName);
			return true;
		} catch (ClassNotFoundException e) {
			System.out.println("驱动类 " + driverClassName + " 加载失败");
		}
		return false;
	}
 
	/**
	 * 专门检查缓存的连接是否不可以被使用 ,不可以被使用的话,就返回 true
	 */
	private static boolean invalid() {
		if (conn != null) {
			try {
				if (conn.isClosed() || !conn.isValid(3)) {
					return true;
			   /*
				* isValid方法是判断Connection是否有效,如果连接尚未关闭并且仍然有效,则返回true
				*/
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
 
		/*
		 * conn 既不是 null 且也没有关闭 ,且 isValid 返回 true,说明是可以使用的 (返回false)
		*/
			return false;
		} else {
			return true;
		}
	}
 
	/**
	 * 建立数据库连接
	 */
	public static Connection connect() {
		if (invalid()) { /* invalid为true时,说明连接是失败的 */
			/* 加载驱动 */
			load();
			try {
				/* 建立连接 */
				conn = DriverManager.getConnection(URL, username, password);
			} catch (SQLException e) {
				System.out.println("建立 " + connect + " 数据库连接失败 , " + e.getMessage());
			}
		}
		return conn;
	}
 
	/**
	 * 设置是否自动提交事务
	 **/
	public static void transaction() {
		try {
			conn.setAutoCommit(autoCommit);
		} catch (SQLException e) {
			System.out.println("设置事务的提交方式为 : " + (autoCommit ? "自动提交" : "手动提交") + " 时失败: " + e.getMessage());
		}
	}
 
	/**
	 * 创建 Statement 对象
	 */
	public static Statement statement() {
		Statement st = null;
		connect();
		/* 如果连接是无效的就重新连接 */
		transaction();
		/* 设置事务的提交方式 */
		try {
			st = conn.createStatement();
		} catch (SQLException e) {
			System.out.println("创建 Statement 对象失败: " + e.getMessage());
		}
		return st;
	}
 
	/**
	 * 根据给定的带参数占位符的SQL语句,创建 PreparedStatement 对象
	 * 
	 * @param SQL
	 *            带参数占位符的SQL语句
	 * @return 返回相应的 PreparedStatement 对象
	 */
	private static PreparedStatement prepare(String SQL, boolean autoGeneratedKeys) {
		PreparedStatement ps = null;
		connect();
		/* 如果连接是无效的就重新连接 */
		transaction();
		/* 设置事务的提交方式 */
		try {
			if (autoGeneratedKeys) {
				ps = conn.prepareStatement(SQL, Statement.RETURN_GENERATED_KEYS);
			} else {
				ps = conn.prepareStatement(SQL);
			}
		} catch (SQLException e) {
			System.out.println("创建 PreparedStatement 对象失败: " + e.getMessage());
		}
		return ps;
	}
 
	public static ResultSet query(String SQL, List<Object> params) {
		if (SQL == null || SQL.trim().isEmpty() || !SQL.trim().toLowerCase().startsWith("select")) {
			throw new RuntimeException("你的SQL语句为空或不是查询语句");
		}
		ResultSet rs = null;
		if (params.size() > 0) {
			/* 说明 有参数 传入,就需要处理参数 */
			PreparedStatement ps = prepare(SQL, false);
			try {
				for (int i = 0; i < params.size(); i++) {
					ps.setObject(i + 1, params.get(i));
				}
				rs = ps.executeQuery();
			} catch (SQLException e) {
				System.out.println("执行SQL失败: " + e.getMessage());
			}
		} else {
			/* 说明没有传入任何参数 */
			Statement st = statement();
			try {
				rs = st.executeQuery(SQL); // 直接执行不带参数的 SQL 语句
			} catch (SQLException e) {
				System.out.println("执行SQL失败: " + e.getMessage());
			}
		}
		return rs;
	}
 
	private static Object typeof(Object o) {
		Object r = o;
		if (o instanceof java.sql.Timestamp) {
			return r;
		}
		// 将 java.util.Date 转成 java.sql.Date
		if (o instanceof java.util.Date) {
			java.util.Date d = (java.util.Date) o;
			r = new java.sql.Date(d.getTime());
			return r;
		}
		// 将 Character 或 char 变成 String
		if (o instanceof Character || o.getClass() == char.class) {
			r = String.valueOf(o);
			return r;
		}
		return r;
	}
 
	public static boolean execute(String SQL, Object... params) {
		if (SQL == null || SQL.trim().isEmpty() || SQL.trim().toLowerCase().startsWith("select")) {
			throw new RuntimeException("你的SQL语句为空或有错");
		}
		boolean r = false;
		/* 表示 执行 DDL 或 DML 操作是否成功的一个标识变量 */
		/* 获得 被执行的 SQL 语句的 前缀 */
		SQL = SQL.trim();
		SQL = SQL.toLowerCase();
		String prefix = SQL.substring(0, SQL.indexOf(" "));
		String operation = ""; // 用来保存操作类型的 变量
		// 根据前缀 确定操作
		switch (prefix) {
		case "create":
			operation = "create table";
			break;
		case "alter":
			operation = "update table";
			break;
		case "drop":
			operation = "drop table";
			break;
		case "truncate":
			operation = "truncate table";
			break;
		case "insert":
			operation = "insert :";
			break;
		case "update":
			operation = "update :";
			break;
		case "delete":
			operation = "delete :";
			break;
		}
		if (params.length > 0) { // 说明有参数
			PreparedStatement ps = prepare(SQL, false);
			Connection c = null;
			try {
				c = ps.getConnection();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				for (int i = 0; i < params.length; i++) {
					Object p = params[i];
					p = typeof(p);
					ps.setObject(i + 1, p);
				}
				ps.executeUpdate();
				commit(c);
				r = true;
			} catch (SQLException e) {
				System.out.println(operation + " 失败: " + e.getMessage());
				rollback(c);
			}
		} else { // 说明没有参数
			Statement st = statement();
			Connection c = null;
			try {
				c = st.getConnection();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			// 执行 DDL 或 DML 语句,并返回执行结果
			try {
				st.executeUpdate(SQL);
				commit(c); // 提交事务
				r = true;
			} catch (SQLException e) {
				System.out.println(operation + " 失败: " + e.getMessage());
				rollback(c); // 回滚事务
			}
		}
		return r;
	}
 
	/*
	 * 
	 * @param SQL 需要执行的 INSERT 语句
	 * 
	 * @param autoGeneratedKeys 指示是否需要返回由数据库产生的键
	 * 
	 * @param params 将要执行的SQL语句中包含的参数占位符的 参数值
	 * 
	 * @return 如果指定 autoGeneratedKeys 为 true 则返回由数据库产生的键; 如果指定 autoGeneratedKeys
	 * 为 false 则返回受当前SQL影响的记录数目
	 */
	public static int insert(String SQL, boolean autoGeneratedKeys, List<Object> params) {
		int var = -1;
		if (SQL == null || SQL.trim().isEmpty()) {
			throw new RuntimeException("你没有指定SQL语句,请检查是否指定了需要执行的SQL语句");
		}
		// 如果不是 insert 开头开头的语句
		if (!SQL.trim().toLowerCase().startsWith("insert")) {
			System.out.println(SQL.toLowerCase());
			throw new RuntimeException("你指定的SQL语句不是插入语句,请检查你的SQL语句");
		}
		// 获得 被执行的 SQL 语句的 前缀 ( 第一个单词 )
		SQL = SQL.trim();
		SQL = SQL.toLowerCase();
		if (params.size() > 0) { // 说明有参数
			PreparedStatement ps = prepare(SQL, autoGeneratedKeys);
			Connection c = null;
			try {
				c = ps.getConnection(); // 从 PreparedStatement 对象中获得 它对应的连接对象
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				for (int i = 0; i < params.size(); i++) {
					Object p = params.get(i);
					p = typeof(p);
					ps.setObject(i + 1, p);
				}
				int count = ps.executeUpdate();
				if (autoGeneratedKeys) { // 如果希望获得数据库产生的键
					ResultSet rs = ps.getGeneratedKeys(); // 获得数据库产生的键集
					if (rs.next()) { // 因为是保存的是单条记录,因此至多返回一个键
						var = rs.getInt(1); // 获得值并赋值给 var 变量
					}
				} else {
					var = count; // 如果不需要获得,则将受SQL影像的记录数赋值给 var 变量
				}
				commit(c);
			} catch (SQLException e) {
				System.out.println("数据保存失败: " + e.getMessage());
				rollback(c);
			}
		} else { // 说明没有参数
			Statement st = statement();
			Connection c = null;
			try {
				c = st.getConnection(); // 从 Statement 对象中获得 它对应的连接对象
			} catch (SQLException e) {
				e.printStackTrace();
			}
			// 执行 DDL 或 DML 语句,并返回执行结果
			try {
				int count = st.executeUpdate(SQL);
				if (autoGeneratedKeys) { // 如果企望获得数据库产生的键
					ResultSet rs = st.getGeneratedKeys(); // 获得数据库产生的键集
					if (rs.next()) { // 因为是保存的是单条记录,因此至多返回一个键
						var = rs.getInt(1); // 获得值并赋值给 var 变量
					}
				} else {
					var = count; // 如果不需要获得,则将受SQL影像的记录数赋值给 var 变量
				}
				commit(c); // 提交事务
			} catch (SQLException e) {
				System.out.println("数据保存失败: " + e.getMessage());
				rollback(c); // 回滚事务
			}
		}
		return var;
	}
 
	/** 提交事务 */
	private static void commit(Connection c) {
		if (c != null && !autoCommit) {
			try {
				c.commit();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
 
	/** 回滚事务 */
	private static void rollback(Connection c) {
		if (c != null && !autoCommit) {
			try {
				c.rollback();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
 
	/**
	 * 释放资源
	 **/
	public static void release(Object cloaseable) {
		if (cloaseable != null) {
			if (cloaseable instanceof ResultSet) {
				ResultSet rs = (ResultSet) cloaseable;
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (cloaseable instanceof Statement) {
				Statement st = (Statement) cloaseable;
				try {
					st.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (cloaseable instanceof Connection) {
				Connection c = (Connection) cloaseable;
				try {
					c.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

***学习任何一样东西都有一个过程,不是谁一开就会的,看到这句话的你 ,加油 ! ***

定义MyInvocationHandlerMbatis

/**
 * 功能说明:手写mybatis框架注解版本 <br>
 * 1.使用动态代理技术,获取接口方法上的sql语句<br>
 * 2.根据不同的SQL语句<br>
 */
public class MyInvocationHandlerMbatis implements InvocationHandler {
 
	/**
	 * 这个就是我们要代理的真实对象
	 */
	private Object subject;
 
	/**
	 * 构造方法,给我们要代理的真实对象赋初值
	 * 
	 * @param subject
	 */
	public MyInvocationHandlerMbatis(Object subject) {
		this.subject = subject;
	}
 
	/**
	 * 该方法负责集中处理动态代理类上的所有方法调用。 调用处理器根据这三个参数进行预处理或分派到 
     * 委托类实例上反射执行
	 * 
	 * @param proxy
	 *            代理类实例
	 * @param method
	 *            被调用的方法对象
	 * @param args
	 *            调用参数
	 * @return
	 * @throws Throwable
	 */
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 判断方法上是否有ExtInsert注解
		ExtInsert extInsert = method.getAnnotation(ExtInsert.class);
		if (extInsert != null) {
			return insertSQL(extInsert, method, args);
		}
		// 判断方法上注解类型
		ExtSelect extSelect = method.getAnnotation(ExtSelect.class);
		if (extSelect != null) {
			return selectMybatis(extSelect, method, args);
		}
		return null;
	}
 
	public int insertSQL(ExtInsert extInsert, Method method, Object[] args) {
		// 获取注解上的sql
		String insertSql = extInsert.value();
		System.out.println("sql:" + insertSql);
		// 获取方法上的参数
		Parameter[] parameters = method.getParameters();
		// 将方法上的参数存放在Map集合中
		ConcurrentHashMap<Object, Object> parameterMap = getExtParams(parameters, args);
		// 获取SQL语句上需要传递的参数
		String[] sqlParameter = SQLUtils.sqlInsertParameter(insertSql);
		List<Object> parameValues = new ArrayList<>();
		for (int i = 0; i < sqlParameter.length; i++) {
			String str = sqlParameter[i];
			Object object = parameterMap.get(str);
			parameValues.add(object);
		}
		// 将SQL语句替换为?号
		String newSql = SQLUtils.parameQuestion(insertSql, sqlParameter);
		System.out.println("newSql:" + newSql);
		// 调用jdbc代码执行
		int insertResult = JDBCUtils.insert(newSql, false, parameValues);
		return insertResult;
	}
 
	public Object selectMybatis(ExtSelect extInsert, Method method, Object[] args) throws SQLException {
		try {
			// 获取查询SQL语句
			String selectSQL = extInsert.value();
			// 将方法上的参数存放在Map集合中
			Parameter[] parameters = method.getParameters();
			// 获取方法上参数集合
			ConcurrentHashMap<Object, Object> parameterMap = getExtParams(parameters, args);
			// 获取SQL传递参数
			List<String> sqlSelectParameter = SQLUtils.sqlSelectParameter(selectSQL);
			// 排序参数
			List<Object> parameValues = new ArrayList<>();
			for (int i = 0; i < sqlSelectParameter.size(); i++) {
				String parameterName = sqlSelectParameter.get(i);
				Object object = parameterMap.get(parameterName);
				parameValues.add(object.toString());
			}
			// 变为?号
			String newSql = SQLUtils.parameQuestion(selectSQL, sqlSelectParameter);
			System.out.println("执行SQL:" + newSql + "参数信息:" + parameValues.toString());
			// 调用JDBC代码查询
			ResultSet rs = JDBCUtils.query(newSql, parameValues);
			// 获取返回类型
			Class<?> returnType = method.getReturnType();
			if (!rs.next()) {
				// 没有查找数据
				return null;
			}
			// 向上移动
			rs.previous();
			// 实例化对象
			Object newInstance = returnType.newInstance();
			while (rs.next()) {
				for (String parameterName : sqlSelectParameter) {
					// 获取集合中数据
					Object value = rs.getObject(parameterName);
					// 查找对应属性
					Field field = returnType.getDeclaredField(parameterName);
					// 设置允许私有访问
					field.setAccessible(true);
					// 赋值参数
					field.set(newInstance, value);
				}
			}
			return newInstance;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
 
	private ConcurrentHashMap<Object, Object> getExtParams(Parameter[] parameters, Object[] args) {
		// 获取方法上参数集合
		ConcurrentHashMap<Object, Object> parameterMap = new ConcurrentHashMap<>();
		for (int i = 0; i < parameters.length; i++) {
			// 参数信息
			Parameter parameter = parameters[i];
			ExtParam extParam = parameter.getDeclaredAnnotation(ExtParam.class);
			// 参数名称
			String paramValue = extParam.value();
			// 参数值
			Object oj = args[i];
			parameterMap.put(paramValue, oj);
		}
		return parameterMap;
	}
}

定义SqlSession

/**
 * 获取SqlSession对象<br>
 */
public class SqlSession {
 
	// 获取getMapper
	public static <T> T getMapper(Class<T> clas)
		throws IllegalArgumentException, InstantiationException, IllegalAccessException {
		return (T) Proxy.newProxyInstance(clas.getClassLoader(), new Class[] { clas },
				new MyInvocationHandlerMbatis(clas));
	}
}

定义SQLUtils


/**
 * SQL拼接<br>
 */
public class SQLUtils {
	/**
	 * 
	 * 获取Insert语句后面values 参数信息<br>
	 * @param sql
	 * @return
	 */
	public static String[] sqlInsertParameter(String sql) {
		int startIndex = sql.indexOf("values");
		int endIndex = sql.length();
		String substring = sql.substring(startIndex + 6, endIndex).replace("(", "").replace(")", "").replace("#{", "")
				.replace("}", "");
		String[] split = substring.split(",");
		return split;
	}
 
	/**
	 * 
	 * 获取select 后面where语句<br>
	 * @param sql
	 * @return
	 */
	public static List<String> sqlSelectParameter(String sql) {
		int startIndex = sql.indexOf("where");
		int endIndex = sql.length();
		String substring = sql.substring(startIndex + 5, endIndex);
		String[] split = substring.split("and");
		List<String> listArr = new ArrayList<>();
		for (String string : split) {
			String[] sp2 = string.split("=");
			listArr.add(sp2[0].trim());
		}
		return listArr;
	}
 
	/**
	 * 将SQL语句的参数替换变为?<br>
	 * @param sql
	 * @param parameterName
	 * @return
	 */
	public static String parameQuestion(String sql, String[] parameterName) {
		for (int i = 0; i < parameterName.length; i++) {
			String string = parameterName[i];
			sql = sql.replace("#{" + string + "}", "?");
		}
		return sql;
	}
 
	public static String parameQuestion(String sql, List<String> parameterName) {
		for (int i = 0; i < parameterName.size(); i++) {
			String string = parameterName.get(i);
			sql = sql.replace("#{" + string + "}", "?");
		}
		return sql;
	}
 
	public static void main(String[] args) {
		// String sql = "insert into user(userName,userAge)
		// values(#{userName},#{userAge})";
		// String[] sqlParameter = sqlInsertParameter(sql);
		// for (String string : sqlParameter) {
		// System.out.println(string);
		// }
		List<String> sqlSelectParameter = SQLUtils
				.sqlSelectParameter("select * from User where userName=#{userName} and userAge=#{userAge} ");
		for (String string : sqlSelectParameter) {
			System.out.println(string);
		}
	}
}

运行效果

UserDao mapper = SqlSession.getMapper(UserDao.class);
		int insertUser = mapper.insertUser(22, "韩信");
		System.out.println("影响行数:" + insertUser);
		User user = mapper.selectUser("韩信", 21);
		System.out.println("查询结果:" + user.getUserName() + "," + user.getUserAge());

1.5 MyBatis整体架构

在这里插入图片描述
在这里插入图片描述

快速入门(quick start)

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.2.8</version>
</dependency>

中央仓库地址: https://mvnrepository.com/tags/maven

ORM关系映射的实体类

实体类 ORM 关系映射 和数据的字段 一 一 对应, 进行getter setter 封装 用于进行赋值和取值, toString()用于打印输出信息

import java.text.SimpleDateFormat;
import java.util.Date;

public class User {
    private String id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private Integer sex;
    private Date birthday;
    private String created;
    private String updated;

    public String getId() {
        return id;
    }

    public void setId(String 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 String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getCreated() {
        return created;
    }

    public void setCreated(String created) {
        this.created = created;
    }

    public String getUpdated() {
        return updated;
    }

    public void setUpdated(String updated) {
        this.updated = updated;
    }

    @Override
    public String toString() {
        return "User{" +
                "id='" + id + '\'' +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", birthday='" + new SimpleDateFormat("yyyy-MM-dd").format(birthday) + '\'' +
                ", created='" + created + '\'' +
                ", updated='" + updated + '\'' +
                '}';
    }
}

连接数据库的信息配置

<?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>
<properties>
	<property name="driver" value="com.mysql.jdbc.Driver"/>
	<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybat2?useUnicode=true&amp;characterEncoding=utf-8&amp;allowMultiQueries=true"/>
	<property name="username" value="root"/>
    	<property name="password" value="123456"/>
   </properties>

   <!-- 环境,可以配置多个,default:指定采用哪个环境 -->
   <environments default="test">
      <!-- id:唯一标识 -->
      <environment id="test">
         <!-- 事务管理器,JDBC类型的事务管理器 事务管理交给Mybatis-->
         <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-110" />
            <property name="username" value="root" />
            <property name="password" value="123456" />
         </dataSource>
      </environment>
      <environment id="development">
         <!-- 事务管理器,JDBC类型的事务管理器 -->
         <transactionManager type="JDBC" />
         <!-- 数据源,池类型的数据源 -->
         <dataSource type="POOLED">
            <property name="driver" value="${driver}" /> <!-- 配置了properties,所以可以直接引用 -->
            <property name="url" value="${url}" />
            <property name="username" value="${username}" />
            <property name="password" value="${password}" />
         </dataSource>
      </environment>
   </environments>
  </configuration>

配置配置xxxMapper.xml(MyMapper.xml)

<?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:命名空间,随便写,一般保证命名空间唯一 -->
<mapper namespace="接口的限定类名">
   <!-- statement,内容:sql语句。id:唯一标识,随便写,在同一个命名空间下保持唯一
      resultType:sql语句查询结果集的封装类型,tb_user即为数据库中的表
    -->
    <!--和接口的id形成对应关系-->
   <select id="selectUser" resultType="com.zpc.mybatis.User">
      select * from tb_user where id = #{id}
   </select>

修改成直接连接的,之后详解(MyBatis-Config.xml)

<?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>
   <!-- 环境,可以配置多个,default:指定采用哪个环境 -->
   <environments default="test">
      <!-- id:唯一标识 -->
      <environment id="test">
         <!-- 事务管理器,JDBC类型的事务管理器 -->
         <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/MyBatistwo" />
            <property name="username" value="root" />
            <property name="password" value="123456" />
         </dataSource>
      </environment>
   </environments>
   <mappers>
   <!--导入映射文件-->
     <mapper resource="mappers/MyMapper.xml" />
   </mappers>
</configuration>

测试MyBais(SqlSessiFactory)

		// 指定全局配置文件
        String resource = "mybatis-config.xml";
        // 通过IO流 读取配置文件
        InputStream in= Resources.getResourceAsStream(resource);
        // 构建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
          // 获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession(); 
      try {
         // 操作CRUD,第一个参数:指定statement,规则:命名空间+“.”+statementId
         // 第二个参数:指定传入sql的参数:这里是用户id
         User user = sqlSession.selectOne("MyMapper.selectUser", 1);
         System.out.println(user);
      } finally {
      //关闭流
         sqlSession.close();
      }
   }

目录结构

在这里插入图片描述

引入日志 依赖

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.5</version>
</dependency>

添加log4j.properties

log4j.rootLogger=DEBUG,A1
log4j.logger.org.apache=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

显示结果

2018-06-30 19:53:37,554 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection
2018-06-30 19:53:37,818 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Created connection 2094411587.
2018-06-30 19:53:37,818 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7cd62f43]
2018-06-30 19:53:37,863 [main] [MyMapper.selectUser]-[DEBUG] ==>  Preparing: select * from tb_user where id = ? 
2018-06-30 19:53:37,931 [main] [MyMapper.selectUser]-[DEBUG] ==> Parameters: 1(Integer)
2018-06-30 19:53:37,953 [main] [MyMapper.selectUser]-[DEBUG] <==      Total: 1
User{id='1', userName='zpc', password='123456', name='李白', age=11, sex=1, birthday='1990-09-02', created='2018-06-30 18:20:18.0', updated='2018-06-30 18:20:18.0'}
2018-06-30 19:53:37,954 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7cd62f43]
2018-06-30 19:53:37,954 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@7cd62f43]
2018-06-30 19:53:37,955 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Returned connection 2094411587 to pool.

MyBatis使用步骤总结

1)配置mybatis-config.xml 全局的配置文件 (1、数据源,2、外部的mapper)
2)创建SqlSessionFactory
3)通过SqlSessionFactory创建SqlSession对象
4)通过SqlSession操作数据库 CRUD
5)调用session.commit()提交事务
6)调用session.close()关闭会话

posted @ 2019-04-08 16:40  全栈小刘  阅读(190)  评论(0编辑  收藏  举报