持久層之 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()關閉會話

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章