一、原生態(tài)JDBC程序中問(wèn)題的總結(jié)
1.1 JDBC程序
需求:使用jdbc查詢mysql數(shù)據(jù)庫(kù)中用戶的記錄
Statement:向數(shù)據(jù)庫(kù)發(fā)送回個(gè)sql語(yǔ)句
預(yù)編譯Statement: 好處:提高數(shù)據(jù)庫(kù)性能
預(yù)編譯Statement向數(shù)據(jù)庫(kù)發(fā)送一個(gè)sql語(yǔ)句,數(shù)據(jù)庫(kù)執(zhí)行后將執(zhí)行結(jié)果存放在緩存中,下次再執(zhí)行相同的語(yǔ)句會(huì)直接從緩存中讀取
1、 加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)
2、 創(chuàng)建并獲取數(shù)據(jù)庫(kù)鏈接
3、 創(chuàng)建jdbc statement對(duì)象
4、 設(shè)置sql語(yǔ)句
5、 設(shè)置sql語(yǔ)句中的參數(shù)(使用preparedStatement)
6、 通過(guò)statement執(zhí)行sql并獲取結(jié)果
7、 對(duì)sql執(zhí)行結(jié)果進(jìn)行解析處理
8、 釋放資源(resultSet、preparedstatement、connection)
public class JDBCTest {
public static void main(String[] args) {
Connection connection = null;
// 預(yù)編譯的Statement,使用預(yù)編譯的Statement提高數(shù)據(jù)庫(kù)性能
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)
Class.forName("com.mysql.jdbc.Driver");
// 通過(guò)驅(qū)動(dòng)管理類獲取數(shù)據(jù)庫(kù)鏈接
connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test?characterEncoding=utf-8",
"root", "root");
// 定義sql語(yǔ)句 ?表示占位符
String sql = "select * from t_user where username = ?";
//獲取預(yù)處理statement
preparedStatement = connection.prepareStatement(sql);
// 設(shè)置參數(shù),第一個(gè)參數(shù)為sql語(yǔ)句中參數(shù)的序號(hào)(從1開始),第二個(gè)參數(shù)為設(shè)置的參數(shù)值
preparedStatement.setString(1, "王五");
// 向數(shù)據(jù)庫(kù)發(fā)出sql執(zhí)行查詢,查詢出結(jié)果集
resultSet = preparedStatement.executeQuery();
// 遍歷查詢結(jié)果集
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) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
1.2問(wèn)題總結(jié):
上面代碼的問(wèn)題總結(jié)
1、數(shù)據(jù)庫(kù)連接,使用時(shí)就創(chuàng)建,不使用立即釋放,對(duì)數(shù)據(jù)庫(kù)進(jìn)行頻繁連接開啟和關(guān)閉,造成數(shù)據(jù)庫(kù)資源浪費(fèi),影響 數(shù)據(jù)庫(kù)性能。
設(shè)想:使用數(shù)據(jù)庫(kù)連接池管理數(shù)據(jù)庫(kù)連接。
2、將sql語(yǔ)句硬編碼到j(luò)ava代碼中,如果sql 語(yǔ)句修改,需要重新編譯java代碼,不利于系統(tǒng)維護(hù)。
設(shè)想:將sql語(yǔ)句配置在xml配置文件中,即使sql變化,不需要對(duì)java代碼進(jìn)行重新編譯。
3、向preparedStatement中設(shè)置參數(shù),對(duì)占位符號(hào)位置和設(shè)置參數(shù)值,硬編碼在java代碼中,不利于系統(tǒng)維護(hù)。
設(shè)想:將sql語(yǔ)句及占位符號(hào)和參數(shù)全部配置在xml中。
4、從resutSet中遍歷結(jié)果集數(shù)據(jù)時(shí),存在硬編碼,將獲取表的字段進(jìn)行硬編碼,,不利于系統(tǒng)維護(hù)。
設(shè)想:將查詢的結(jié)果集,自動(dòng)映射成java對(duì)象。
二、mybatis原理
2.1 mybatis是什么?
mybatis是一個(gè)持久層的框架,是apache下的頂級(jí)項(xiàng)目。
mybatis托管到goolecode下,再后來(lái)托管到github下(https://github.com/mybatis/mybatis-3/releases)。
mybatis讓程序?qū)⒅饕Ψ旁趕ql上,通過(guò)mybatis提供的映射方式,自由靈活生成(半自動(dòng)化,大部分需要程序員編寫sql)滿足需要sql語(yǔ)句。
mybatis可以將向 preparedStatement中的輸入?yún)?shù)自動(dòng)進(jìn)行輸入映射,將查詢結(jié)果集靈活映射成java對(duì)象。(輸出映射)
2.2 mybatis框架

1、 mybatis配置
SqlMapConfig.xml,此文件作為mybatis的全局配置文件,配置了mybatis的運(yùn)行環(huán)境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作數(shù)據(jù)庫(kù)的sql語(yǔ)句。此文件需要在SqlMapConfig.xml中加載。
2、 通過(guò)mybatis環(huán)境等配置信息構(gòu)造SqlSessionFactory即會(huì)話工廠
3、 由會(huì)話工廠創(chuàng)建sqlSession即會(huì)話,操作數(shù)據(jù)庫(kù)需要通過(guò)sqlSession進(jìn)行。
4、 mybatis底層自定義了Executor執(zhí)行器接口操作數(shù)據(jù)庫(kù),Executor接口有兩個(gè)實(shí)現(xiàn),一個(gè)是基本執(zhí)行器、一個(gè)是緩存執(zhí)行器。
5、 Mapped Statement也是mybatis一個(gè)底層封裝對(duì)象,它包裝了mybatis配置信息及sql映射信息等。mapper.xml文件中一個(gè)sql對(duì)應(yīng)一個(gè)Mapped Statement對(duì)象,sql的id即是Mapped statement的id。
6、 Mapped Statement對(duì)sql執(zhí)行輸入?yún)?shù)進(jìn)行定義,包括HashMap、基本類型、pojo,Executor通過(guò)Mapped Statement在執(zhí)行sql前將輸入的java對(duì)象映射至sql中,輸入?yún)?shù)映射就是jdbc編程中對(duì)preparedStatement設(shè)置參數(shù)。
7、 Mapped Statement對(duì)sql執(zhí)行輸出結(jié)果進(jìn)行定義,包括HashMap、基本類型、pojo,Executor通過(guò)Mapped Statement在執(zhí)行sql后將輸出結(jié)果映射至java對(duì)象中,輸出結(jié)果映射過(guò)程相當(dāng)于jdbc編程中對(duì)結(jié)果的解析處理過(guò)程。
三、入門程序之mybatis增刪改查
3.1 需求
根據(jù)用戶id(主鍵)查詢用戶信息
根據(jù)用戶名稱模糊查詢用戶信息
添加用戶
刪除 用戶
更新用戶
3.2 PC環(huán)境
java環(huán)境:1.7.0_40
eclipse
mysql: 5.7
3.3 創(chuàng)建mysql數(shù)據(jù)庫(kù)
新建數(shù)據(jù)庫(kù)mybatis,新建表user

3.4所需Jar包
MyBatis下載地址:https://github.com/mybatis/mybatis-3/releases
mybatis-3.4.4.jar :核心包
mysql-connector-java-5.1.jar:mysql的驅(qū)動(dòng)包
3.4 工程結(jié)構(gòu)
在eclipse中新建java工程,創(chuàng)建下面的工程結(jié)構(gòu),并把jar把添加到lib中

3.5 配置log4j.properties
開發(fā)環(huán)境 下日志級(jí)別設(shè)置為DEBUG, log4j.rootLogger=DEBUG, stdout; 生產(chǎn)環(huán)境設(shè)置為info或error
# Global logging configuration
#\u5728\u5f00\u53d1\u73af\u5883\u4e0b\u65e5\u5fd7\u7ea7\u522b\u8981\u8bbe\u7f6e\u6210DEBUG\uff0c\u751f\u4ea7\u73af\u5883\u8bbe\u7f6e\u6210info\u6216error
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
3.6 配置SqlMapConfig.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>
<!-- 加載屬性文件 -->
<properties resource="db.properties">
<!--properties中還可以配置一些屬性名和屬性值 -->
<!-- <property name="jdbc.driver" value=""/> -->
</properties>
<!-- 全局配置參數(shù),需要時(shí)再設(shè)置 -->
<!-- <settings>
</settings> -->
<!-- 別名定義 -->
<typeAliases>
<!-- 針對(duì)單個(gè)別名定義
type:類型的路徑
alias:別名
-->
<!-- <typeAlias type="cn.itcast.mybatis.po.User" alias="user"/> -->
<!-- 批量別名定義
指定包名,mybatis自動(dòng)掃描包中的po類,自動(dòng)定義別名,別名就是類名(首字母大寫或小寫都可以)
-->
<package name="cn.itcast.mybatis.po"/>
</typeAliases>
<!-- 和spring整合后 environments配置將廢除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事務(wù)管理,事務(wù)控制由mybatis-->
<transactionManager type="JDBC" />
<!-- 數(shù)據(jù)庫(kù)連接池,由mybatis管理-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 加載 映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml"/>
</mappers>
</configuration>
3.7 根據(jù)用戶id(主鍵)查詢用戶信息
3.7.1 創(chuàng)建po類
在cn.eugene.po下創(chuàng)建user類
package cn.eugene.po;
public class User {
private int id;
private String userName;
private String userAge;
private String userAddress;
public User() {
super();
// TODO Auto-generated constructor stub
}
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the userName
*/
public String getUserName() {
return userName;
}
/**
* @param userName the userName to set
*/
public void setUserName(String userName) {
this.userName = userName;
}
/**
* @return the userAge
*/
public String getUserAge() {
return userAge;
}
/**
* @param userAge the userAge to set
*/
public void setUserAge(String userAge) {
this.userAge = userAge;
}
/**
* @return the userAddress
*/
public String getUserAddress() {
return userAddress;
}
/**
* @param userAddress the userAddress to set
*/
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
@Override
public String toString() {
return "User [id=" + id + ", userName=" + userName + ", userAge=" + userAge + ", userAddress=" + userAddress
+ "]";
}
}
3.7.2 映射文件
在項(xiàng)目目錄的sqlmap下創(chuàng)建user的映射文件userMapper.xml,并配置根據(jù)id查詢用的sql語(yǔ)句
<?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="test">
<!-- 根據(jù)id查詢用戶信息 -->
<select id="findUserById" parameterType="int" resultType="cn.eugene.po.User">
select * from user where id = #{id}
</select>
</mapper>
3.7.3 在SqlMapConfig.xml加載映射文件
<mappers>
<mapper resource="sqlmap/userMapper.xml"/>
</mappers>
3.7.4 編寫測(cè)試程序,根據(jù)id查詢用戶信息
package cn.eugene.first;
import java.io.IOException;
import java.io.InputStream;
import org.junit.Test;
import cn.eugene.po.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisFirst {
@Test
public void findUserByIdTest() throws IOException{
//得到配置文件流
String resource = "SqlMapConfig.xml";
InputStream inputstream = Resources.getResourceAsStream(resource);
//創(chuàng)建會(huì)話工廠,傳入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通過(guò)會(huì)話工廠得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("test.findUserById", "1");
System.out.println(user);
sqlSession.close();
}
@Test
public void deleteUser() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputstream = Resources.getResourceAsStream(resource);
//創(chuàng)建會(huì)話工廠,傳入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通過(guò)會(huì)話工廠得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("test.deleteUser", "2");
sqlSession.commit();
sqlSession.close();
}
@Test
public void updateUser() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputstream = Resources.getResourceAsStream(resource);
//創(chuàng)建會(huì)話工廠,傳入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通過(guò)會(huì)話工廠得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setId(2);
user.setUserName("出運(yùn)費(fèi)");
user.setUserAge("21");
user.setUserAddress("重慶");
sqlSession.update("test.updateUser", user);
sqlSession.commit();
sqlSession.close();
}
}
3.8 添加用戶
sql配置
<insert id="insertUser" parameterType="cn.eugene.po.User">
insert into user(userName,userAge,userAddress)VALUES(#{userName},#{userAge},#{userAddress})
</insert>
測(cè)試方法
@Test
public void insertUser() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputstream = Resources.getResourceAsStream(resource);
//創(chuàng)建會(huì)話工廠,傳入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通過(guò)會(huì)話工廠得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setUserName("出運(yùn)費(fèi)");
user.setUserAge("21");
user.setUserAddress("重慶2");
sqlSession.update("test.insertUser", user);
sqlSession.commit();
sqlSession.close();
}
3.9 刪除用戶更新用戶
sql配置
<!-- 根據(jù)id刪除用戶 -->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<update id="updateUser" parameterType="cn.eugene.po.User">
update user set userName=#{userName},userAge=#{userAge},userAddress=#{userAddress} where id= #{id}
</update>
測(cè)試方法
@Test
public void insertUser() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputstream = Resources.getResourceAsStream(resource);
//創(chuàng)建會(huì)話工廠,傳入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通過(guò)會(huì)話工廠得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setUserName("出運(yùn)費(fèi)");
user.setUserAge("21");
user.setUserAddress("重慶2");
sqlSession.update("test.insertUser", user);
sqlSession.commit();
sqlSession.close();
}
3.10添加用戶主鍵返回
<insert id="insertUser2" parameterType="com.ganlion.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(userName,userAge,userAddress)VALUES(#{userName},#{userAge},#{userAddress})
</insert>
測(cè)試方法
@Test
public void insertUser2(){
InputStream inputstream = Resources.getResourceAsStream(resource);
//創(chuàng)建會(huì)話工廠,傳入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
//通過(guò)會(huì)話工廠得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setUserName("飛天");
user.setUserAge("24");
user.setUserAddress("上海浦江");
session.insert("test.insertUser2", user);
session.commit();
System.out.println("返回的插入的主鍵id:"+user.getId());
session.close();
}
四、總結(jié)
sql配置文件中
parameterType指定輸入?yún)?shù)類型
resultType指定輸出參數(shù)類型
#{}表示一個(gè)占位符,#{}接收輸入?yún)?shù)。#{}可以有效防止sql注入。類型可以是簡(jiǎn)單類型,pojo、hashmap。如果接收簡(jiǎn)單類型,#{}中可以寫成value或其它名稱。
#{}接收pojo對(duì)象值,通過(guò)OGNL讀取對(duì)象中的屬性值,通過(guò)屬性.屬性.屬性...的方式獲取對(duì)象屬性值。
${}表示一個(gè)拼接符號(hào),拼接sql串,會(huì)引起sql 注入存在安全隱患,所以不建議使用${}。${}接收輸入?yún)?shù),類型可以是簡(jiǎn)單類型,pojo、hashmap。如果接收簡(jiǎn)單類型,${}中只能寫成value。
${}接收pojo對(duì)象值,通過(guò)OGNL讀取對(duì)象中的屬性值,通過(guò)屬性.屬性.屬性...的方式獲取對(duì)象屬性值。
五、編寫入門程序可能遇到的問(wèn)題
問(wèn)題一、Could not find resource SqlMapConfig.xml

原因:一開始是因?yàn)槟J(rèn)的情況下,只有src是build path的source folder目錄,自定義的文件夾在Use as Source Folder前只是一個(gè)普通的文件夾,默認(rèn)的情況下不會(huì)被加載,需要手動(dòng)將自定義的文件夾加載為source folder。也就是之前所說(shuō)的步驟。
解決辦法:右鍵點(diǎn)擊SqlMapConfig.xml所在的文件夾(我的是config)------>Build Path------>Use as Source Folder
參考mybatis中遇到Could not find resource SqlMapConfig.xml
問(wèn)題二、當(dāng)查詢數(shù)據(jù)庫(kù)數(shù)據(jù)的時(shí)候,控制臺(tái)System.out.println(user)輸出了NULL
注意sql配置文件查詢的字段和數(shù)據(jù)庫(kù)對(duì)應(yīng)