前言
Java學(xué)到一定程度涩惑,框架終歸是不可避免的奉呛,畢竟程序開發(fā)很多時候不是一個人的事兒畔勤。這兩天學(xué)習(xí)了MyBatis框架胯陋,想著結(jié)合一下這幾天學(xué)到的東西和實習(xí)的經(jīng)驗總結(jié)一下蕊温。大概的思路就是從JDBC的缺陷到MyBatis的介紹和運行流程,再就是Mybatis的一個增刪改查小程序遏乔;然后是企業(yè)中MyBatis進(jìn)行數(shù)據(jù)庫開發(fā)時采用Dao方法和Mapper方法的一個介紹寿弱,最后是和Spring的一個整合。
也希望大家提出寶貴的建議按灶。
JDBC
JDBC小程序
DBHelper(數(shù)據(jù)庫連接類)
/**
* @param連接數(shù)據(jù)庫
* */
public class DBHelper {
//參數(shù)配置
//public static final String url = "jdbc:mysql://127.0.0.1/test";
public static final String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf-8";
public static final String name = "com.mysql.jdbc.Driver";
public static final String user = "root";
public static final String password = "8888";
public static Connection conn= null;
public DBHelper() {
// TODO Auto-generated constructor stub
try{
Class.forName(name); //加載數(shù)據(jù)庫驅(qū)動
conn = DriverManager.getConnection(url, user, password); //通過驅(qū)動管理類獲取數(shù)據(jù)庫鏈接
}catch(Exception e){
e.printStackTrace();
}
}
public static void Close(){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
testJdbc(測試SQL查詢)
public class testJdbc {
private static String sql = null;
private static DBHelper db = null;
public static PreparedStatement pst = null;
public static ResultSet ret = null;
public static void main(String[] args) {
// TODO Auto-generated method stub
db = new DBHelper(); //通過構(gòu)造器連接到數(shù)據(jù)庫
System.out.println(db.conn);
db.Close();
/*
//sql = "INSERT INTO `test`.`user` (`Username`, `Password`, `Age`, `Address`, `UserId`) VALUES"
// + " ('bb', '1234', '23', 'hubei', '4');"; //插入語句
//sql = "UPDATE `test`.`user` SET `Username`='ouou' WHERE `UserId`='1';"; //更新語句
sql = "DELETE * where `UserId` = '2'"; //刪除語句
String sql1 = "select * from user"; //選擇語句
try {
pst = db.conn.prepareStatement(sql);
pst.execute();
ret = pst.executeQuery(sql1);
while(ret.next()){
String name = ret.getString(1);
String pass = ret.getString(2);
String age = ret.getString(3);
String addr = ret.getString(4);
String id = ret.getString(5);
System.out.println(id+" "+name+" "+pass+" "+age+" "+addr);
}
}catch(SQLException e){
e.printStackTrace();
}*/
}
}
問題總結(jié)
總結(jié)網(wǎng)上搜集到東西和自己實際遇到的歸納為以下幾點:
- 數(shù)據(jù)庫頻繁地連接開啟和關(guān)閉症革,造成資源的浪費。(使用數(shù)據(jù)庫連接池進(jìn)行管理)
- SQL語句鸯旁、preparedStatement設(shè)置參數(shù)硬編碼在Java代碼中噪矛,不利于系統(tǒng)維護(hù)量蕊。(使用xml進(jìn)行配置)
- resultSet遍歷結(jié)果集數(shù)據(jù)時,也存在硬編碼艇挨。(將查詢的結(jié)果集残炮,自動映射成Java對象)
MyBatis
為什么選擇MyBatis
MyBatis 是支持定制化 SQL、存儲過程以及高級映射的優(yōu)秀的持久層框架缩滨。MyBatis 避免了幾乎所有的 JDBC
代碼和手工設(shè)置參數(shù)以及抽取結(jié)果集势就。MyBatis 使用簡單的 XML 或注解來配置和映射基本體,將接口和 Java的
POJOs(Plain Old Java Objects,普通的 Java對象)映射成數(shù)據(jù)庫中的記錄脉漏。(選自官網(wǎng))
- 也就是說開發(fā)者只需要關(guān)注SQL本身苞冯,而不需要花費精力去處理例如注冊驅(qū)動、創(chuàng)建connection侧巨、創(chuàng)建statement舅锄、手動設(shè)置參數(shù)、結(jié)果集檢索等jdbc的過程代碼司忱。MyBatis通過xml或注解的方式將要執(zhí)行的各種statement(statement皇忿,preparedStatement、CallableStatement)配置起來坦仍,并通過Java對象和statement中的SQL進(jìn)行映射生成最終執(zhí)行的SQL語句鳍烁,最后又mybatis框架執(zhí)行SQL并將結(jié)果映射成Java對象并返回。
MyBatis是什么
MyBatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation 遷移到了google code繁扎,并且改名為MyBatis老翘,實質(zhì)上Mybatis對ibatis進(jìn)行一些改進(jìn)。
MyBatis框架圖
MyBatis的運行流程
- 在SQLMapConfig.xml(mybati的全局配置文件)中配置mybatis的運行環(huán)境等信息锻离。并在其中加載mapper.xml(sql映射文件铺峭,配置了操作數(shù)據(jù)庫的SQL語句)文件。
- 通過mybatis環(huán)境等配置信息構(gòu)造SQLSessionFactory會話工廠汽纠。
- 由會話工廠創(chuàng)建SQLSession來操作數(shù)據(jù)庫卫键。
- mybatis底層自定義了Executor執(zhí)行器接口操作數(shù)據(jù)庫,Executor接口有基本執(zhí)行器和緩存執(zhí)行器兩個實現(xiàn)虱朵。
- Mapped Statement也是mybatis一個底層封裝對象莉炉,包裝了mybatis配置信息及SQL映射信息等。mapper.xml文件中一個SQL對應(yīng)一個Mapped Statement 對象碴犬,SQL的id即是Mapped Statement的id絮宁。
- Mapped Statement對SQL執(zhí)行輸入?yún)?shù)進(jìn)行定義,包括HashMap服协、基本類型绍昂、pojo,Executor通過Mapped Statement在執(zhí)行SQL前將輸入的Java對象映射至SQL中,輸入?yún)?shù)映射就是jdbc編程中對preparedStatement設(shè)置參數(shù)窘游。
- Mapped Statement對SQL執(zhí)行輸出結(jié)果進(jìn)行定義唠椭,包括HashMap、基本類型忍饰、pojo,Executor通過Mapped Statement在執(zhí)行SQL后將輸出結(jié)果映射至Java對象中贪嫂,輸出結(jié)果映射過程相當(dāng)于jdbc編程中結(jié)果的解析處理過程。
MyBatis的優(yōu)缺點及Hibernate的簡短比較
Mybatis和hibernate的不同之處在于它不是一個完全的ORM框架艾蓝,它需要開發(fā)者自己編寫SQL語句力崇,不過mybatis可以通過xml或注解方式靈活配置要運行的SQL語句,并將Java對象和SQL語句映射生成最終執(zhí)行的SQL赢织,最后將SQL執(zhí)行的結(jié)果再映射生成Java對象亮靴。
MyBatis相對于hibernate來說,學(xué)習(xí)門檻低敌厘,易于學(xué)習(xí),靈活度也高朽合,適合對關(guān)系數(shù)據(jù)模型要求不高的軟件開發(fā)俱两,以為其需求變化頻繁。正是因為mybatis的高度靈活曹步,所以它無法做到數(shù)據(jù)庫無關(guān)性宪彩,需要實現(xiàn)支持多種數(shù)據(jù)庫的軟件則需要自定義多套SQL映射文件。
Hibernate對象/關(guān)系映射能力強(qiáng)讲婚,數(shù)據(jù)庫無關(guān)性好尿孔,對于關(guān)系模型要求高的軟件(例如需求固定的定制化軟件)如果用hibernate開發(fā)可以節(jié)省很多代碼,提高效率筹麸。但是Hibernate的學(xué)習(xí)門檻高活合,要精通門檻更高,而且怎么設(shè)計O/R映射物赶,在性能和對象模型之間如何權(quán)衡白指,以及怎樣用好Hibernate需要具有很強(qiáng)的經(jīng)驗和能力才行。
所以如是說:沒有最好的框架酵紫,只有最適合的框架告嘲。
簡單的CRUD入門程序
導(dǎo)入的包:
項目工程結(jié)構(gòu):
輸出日志信息配置(log4j.properties):
# Global logging configuration
log4j.rootLogger = DEBUG,stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %5p [%t] - %m%n
全局配置文件(SqlMapConfig.xml):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 加載屬性文件 -->
<properties resource="db.properties">
</properties>
<!-- 和spring整合后 environments配置將廢除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事務(wù)管理 -->
<transactionManager type="JDBC" />
<!-- 數(shù)據(jù)庫連接池-->
<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>
數(shù)據(jù)庫配置文件(db.properties)
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
jdbc.username=root
jdbc.password=8888
User po類:
package com.howie.po;
import java.io.Serializable;
import java.util.Date;
/**
* @param User po類
*/
public class User implements Serializable {
private int id;
private String username;// 用戶名
private String sex;//性別
private Date birthday;// 生日
private String address;// 地址
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
映射文件user.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 對SQL進(jìn)行分類話管理,理解SQL隔離
注意:是用mapper代理方法開發(fā)奖地,namespace有特殊重要的作用
-->
<mapper namespace = "test">
<!-- 在映射文件中配置很多SQL語句 -->
<!-- 查找 -->
<select id = "findUserById" parameterType="int" resultType="com.howie.po.User">
SELECT * FROM test.user where id = #{value}
</select>
<!-- 添加用戶 -->
<insert id="insertUser" parameterType="com.howie.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
<!-- 刪除用戶 -->
<delete id="deleteUserById" parameterType="int">
delete from user where id=#{id}
</delete>
<!-- 更新用戶 -->
<update id="updateUser" parameterType="com.howie.po.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}
where id=#{id}
</update>
</mapper>
測試文件MybatisTest類
(避免麻煩橄唬,測試一個查找語句,讀者感興趣的可以自行實現(xiàn)其他功能)
package com.howie.test;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.howie.po.User;
public class MybatisTest {
public static void findUserByIdTest() throws IOException{
//配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//創(chuàng)建回話工廠
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(inputStream);
//通過工廠得到SQLSession
SqlSession ss = sf.openSession();
//通過SQLSession操作數(shù)據(jù)庫
//第一個參數(shù):映射文件中statement的id参歹,等于=namespace+statement的id
//第二個參數(shù):制定和映射文件中所匹配的parameterType得參數(shù)
//ss.selectOne結(jié)果是與映射文件中所匹配的resultType類型的對象
User user = ss.selectOne("test.findUserById", 1);
System.out.println(user);
System.out.print(user.getAddress()+" "+user.getId()+" "+user.getUsername()+
" "+user.getSex());
System.out.println();
//釋放資源
ss.close();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
findUserByIdTest();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
未完待續(xù).......