Java框架之Mybatis(一)


一、Mybatis 簡介

Mybatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation 遷移到了google code,並且改名為Mybatis  , 2013年11月遷移到Github , iBATIS一詞來源於“internet”和“abatis”的組合,是一個基於Java的持久層框架。iBATIS提供的持久層框架包括SQL Maps和Data Access Objects(DAO)Mybatis 是支持普通 SQL查詢,存儲過程和高級映射的優秀持久層框架。Mybatis 消除了幾乎所有的JDBC代碼和參數的手工設置以及結果集的檢索。Mybatis 使用簡單的 XML或注解用於配置和原始映射,將接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記錄。

二、Mybatis 的執行框架

1) SqlMapConfig.xml 文件 //名稱不一定是這個名稱 類似hibernate中的主配置文件

主配置文件 配置數據源,事務等運行環境,配置映射文件 (xxXmapper.xml... 多個)

2) SessionFactory

會話工廠,它是根據配置文件創建的,用來創建  SqlSession

3) SqlSession

會話 ,是一個接口,面向用戶的接口,主要用來進行數據庫操作

4) Executor

執行器,是底層封裝的一個對象,是一個接口(底層有兩個實現,基本執行器,緩存執行器)事實上 SqlSession 的內部就是通過該接口來執行sql語句的

5) MappedStatement 底層封裝的對象,封裝sql ,輸入參數,輸出結果類型等

三、第一個hello world 程序

1) 導包

asm-3.3.1.jar

cglib-2.2.2.jar

commons-logging-1.1.1.jar

javassist-3.17.1-GA.jar

log4j-1.2.17.jar

log4j-api-2.0-rc1.jar

log4j-core-2.0-rc1.jar

Mybatis-3.2.6.jar

slf4j-api-1.7.5.jar

slf4j-log4j12-1.7.5.jar

2) 在config里建一個配置文件(數據庫相關的) mydbconfig.properties , 內容如下

db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/shop
db.username=admin
db.password=root

3) 建立 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="mydbconfig.properties" />
                
                <environments default="development">
                    <environment id="development">
                        <transactionManager type="JDBC" />
                        <dataSource type="POOLED">  //POOLED指的是org.apache.ibatis.datasource.pooled.PooledDataSource, 一個數據源的實現類  
                            <property name="driver" value="${db.driver}" />
                            <property name="url" value="${db.url}" />
                            <property name="username" value="${db.username}" />
                            <property name="password" value="${db.password}" />
                        </dataSource>
                    </environment>
                </environments>
            
                 <mappers>
                    <mapper resource="sqlmap/UserInfo.xml" />
                </mappers>
            </configuration>   

4) 編寫映射文件 (其實就是bean 對應的映射文件 相當於 hibernate 中的 UsesrInfo.hbm.xml 之類的 )

命名規則 :

== UserInfo.xml  //過去的ibatis中

== 如果使用了mapper 代理  命名規則變為  UserInfoMapper.xml

 //UserInfo.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="test">
                    <select id="getuser_byid"  parameterType="int" resultType="cat.beans.UserInfo" >
                        select * from userInfo where id=#{id}  //如是簡單類型,id可以寫成任意名字
                    </select>
</mapper>

說明: namespace 是命名空間,用來對sql進行隔離 ,注意,如果使用mapper代理的方式開發,它就有特殊的作用

-- <select id="getuser_byid" ... > 這個id 就是sql的標識,其實將來要封裝到 MappedStatement 中

-- #{ } 代表占位

--  如是參數是簡單類型,{} 中的名字可以任意

--  resultType 表示返回的java對象的類型,表示要將查詢結果映射成什么樣的java對象

5) 在主配置文件中引入這個映射文件

主配置文件中加入

<mappers>
         <mapper resource="sqlmap/UserInfo.xml" />
</mappers>
//上面的主配置文件中其實已經加入了

6)測試

static void test(){
//加載主配置文件
            InputStream in=Test.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml");
            //InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");    //Resources是mhybatis 提供的
                
            SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
            SqlSession session =factor.openSession();
                
                                                   //第一個參數,是sql的id (是映射文件中的statement的id) = 名稱空間+sql的id名稱 ,
            UserInfo user=session.selectOne("test.getuser_byid",1); //注意,這里的1 不能定成 "1"
            System.out.println(user);
            session.close();        
            }

在上例的基礎上,再添一個模糊查詢的例子 

在 UserInfo.xml 中 加入

<select id="getuser_biname" parameterType="string" resultType="cat.beans.UserInfo">
//select * from userInfo where userName  like #{value}   //不行,  它會拼成like '張三'
select * from userInfo where userName like  '%${value}%'  // ${value} 表示會把傳過來的值,直接拼到串上,有可能有sql注入問題,而且
// 如果parameterType 是簡單類型,則${ } 中間的必須寫成 value
</select>
static void test() throws IOException{
                    InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
                    SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
                    SqlSession session =factor.openSession();
                    
                    UserInfo user=session.selectOne("test.getuser_byid",1); //注意,這里的1 不能定成 "1"
                    System.out.println(user);
                    
                    session.close();
                    
                }

總結:

#{} Mybatis 將  #{} 解釋為jdbc PreparedStatement  的一個參數標記  // 就是 select * from t where id= ? 中的 ?

${} 將它直接解釋為字符串

理解這兩者的區別是很有用的, 因為在某些SQL語句中並不能使用參數標記(parameter markers)。

那如果有like查詢要怎么辦呢? 可以這樣sql寫成第一種 #{} ,傳參的時候如下   

"%張三%"
selectOne   //返回一個對象
selectList  //返回一組對象 兩者 resultType="cat.beans.UserInfo" 都正常

在上例的基礎上,再增加一個添加用戶的功能

//對於添加這類方法,是沒有resultType的
<insert id="add_user" parameterType="cat.beans.UserInfo"  >
        insert into userInfo (userName,password,note) values (#{userName},#{password}, #{note} ) //后面不要寫上分號
</insert>
        tatic void test3() throws IOException{
                        
                        InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
                        SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
                        SqlSession session =factor.openSession();
                        
                        UserInfo user=new UserInfo();
                        user.setUserName("陳鵬飛");
                        user.setPassword("admin");
                        user.setNote("這是備注");
                        
                        int result=session.insert("test.add_user",user); 

// 對於inser,雖然沒有為sql聲明反回類型,但也能正確的取到反回值的,它是整型 session.commit(); //不要忘了提交事務 System.out.println(result); //能得到正確的值 1 session.close(); }

在上面的基礎上,再添加刪除的和修改的功能

<delete id="deluser_byid" parameterType="int" > 
                    delete from userInfo where id=#{id}
                </delete>
                
                <update id="update_user" parameterType="cat.beans.UserInfo" > <!-- 傳過來的userInfo對象中要有id -->
                   update userInfo set userName= #{userName},password= #{password}, note =#{note} where id= #{id}
                </update>
//修改
                    static void test4() throws IOException{
    
                        InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
                        SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
                        SqlSession session =factor.openSession();
                        
                        UserInfo user=session.selectOne("test.getuser_byid",1);
                        user.setUserName("english"); 
                        user.setPassword("englishxxx");
                        user.setNote("englishxxx");
                      int result= session.update("test.update_user",user);
                      session.commit();
                      System.out.println("修改成功: " + result);
                        
                        session.close();
                    }
                    
                 //刪除
                    static void test5() throws IOException{
                        InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
                        SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
                        SqlSession session =factor.openSession();
                        int result= session.delete("test.deluser_byid",10);
                        session.commit();
                        System.out.println("刪除成功: " + result);
                        session.close();
                    }

四、返回自增主鍵

mysql 有一個函數 last_insert_id() 可以調用它得到最后一條插入語句生成的自增主鍵。

在上面的用戶添加的例子上

<insert id="add_user" parameterType="cat.beans.UserInfo"  >
        <selectKey order="AFTER" keyProperty="id" resultType="int">   //resultType 必填 keyProperty的id 就是userInfo.id
                      select  last_insert_id()
                     //elect new uuid();  //這是mysql生成uui的寫法 (32位數字或字母,4位是 -)  如果這樣,上面的AFTER要改成before
                     //select 序列名.nextval 這是oracle中的寫法
       </selectKey>
                insert into userInfo (userName,password,note) values (#{userName},#{password}, #{note} ) 
</insert>

說明:

order="AFTER" 指的是 要在這條語句執行之后取得生成的主鍵,它還有另一個取值 BEFORE

非自增主鍵,想取得,要用BEFORE,但生成主鍵的方式應該是上面的紅色的注起來的方式。

注意,如果用的是后面的方式,則下面的sql要寫上id

例子:生成 uuid型的主鍵

 <insert id="add_user_new" parameterType="cat.beans.UserInfo"  >
                <selectKey order="BEFORE" keyProperty="id" resultType="string">   //注意返回類型,注意前面要寫成 BEFORE
                    select  uuid()
                </selectKey>
                insert into userInfo (id,userName,password,note) values (#{id},#{userName},#{password}, #{note} ) 
                //注意要把id這列也寫上
            </insert>
            
                UserInfo user=new UserInfo();
            //user.setId() 不用寫了,因為主鍵由Mybatis生成
                
                user.setUserName("鄭某某");
                user.setPassword("admin");
                user.setNote("這是備注");
                
                session.insert("test.add_user_new",user);
                session.commit(); 
    
                System.out.println(user.getId());  //可以取到主鍵 369010c6-e631-1033-b927-e281dfdaa6b0

五、dao層的開發

SessionFactory 可以做成單例 (未來會交給Spring管理)

SqlSession  是線程不安全的, 用的時候,要在方法體內 , 這樣它就是一個局部變量,千萬不要把它寫成類成員

Mybatis 開發DAO 有兩種方式

原始的方式 ,手寫dao 和實現類

//接口 :
public interface IUserDao {
                    int addUser(UserInfo user);
                    UserInfo getUserById(int id);
                }
                
//實現類
public class UserDaoImplTest {
                    private IUserDao _dao ;
                    @Before
                    public void setUp() throws Exception {
                        InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
                        SqlSessionFactory factor=new SqlSessionFactoryBuilder().build(in);
                        _dao=new UserDaoImpl(factor);
                    }
                
                    @Test
                    public void testAddUser() {
                        UserInfo user=new UserInfo();
                        user.setUserName("周周");
                        user.setPassword("admin");
                        
                        int result=_dao.addUser(user);
                        System.out.println("ok"+result);
                    }
                
                    @Test
                    public void testGetUserById() {
                        UserInfo user=_dao.getUserById(2);
                        System.out.println(user);
                    }
                
                }

測試用例

使用 mapper 代理的方式  ,只需要mapper接口 (相當於dao接口)

public class UserDaoImpl implements IUserDao {
                private SqlSessionFactory _factory;
                
                public UserDaoImpl(SqlSessionFactory factory){
                    this._factory=factory;  //由外界注入 SqlSessionFactory
                }
                
                //添加用戶
                public int addUser(UserInfo user) {
                    SqlSession s =_factory.openSession();
                    int result=s.insert("test.add_user",user);
                    s.commit();
                    return result;
                }
            
                //查詢用戶
                public UserInfo getUserById(int id) {
                    SqlSession s =_factory.openSession();
                    UserInfo user=s.selectOne("test.getuser_byid",id);
                    s.commit();
                    return user;
                }
            
            }

配置文件

<mapper namespace="test">
                <select id="getuser_byid"  parameterType="int" resultType="cat.beans.UserInfo" >
                    select * from userInfo where id=#{id} 
                </select>
                
                <insert id="add_user" parameterType="cat.beans.UserInfo"  >
                    <selectKey order="AFTER" keyProperty="id" resultType="int">  
                        select  last_insert_id()
                    </selectKey>
                    insert into userInfo (userName,password,note) values (#{userName},#{password}, #{note} ) 
                </insert>
                
                 ... 其他的略
                 
            </mapper>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM