一.傳統jdbc存在的問題
1.創建數據庫的連接存在大量的硬編碼,
2.執行statement時存在硬編碼.
3.頻繁的開啟和關閉數據庫連接,會嚴重影響數據庫的性能,浪費數據庫的資源.
4.存在大量的重復性編碼
二.mybatis執行流程
Mybatis基本的執行流程如下圖所示:
三.mybatis入門程序
3.1 通過mybatis完成通過主鍵(id)查詢用戶(user)
3.1.1.項目環境搭建
建立的是Java項目.采用的mybatis版本為3.2.7.
需要導入mybatis核心jar包和依賴jar包.建立log4j.properties配置文件記錄日志.
項目搭建后的架構如下:
3.1.2.在Classpath路徑下建立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> <!-- 配置mybatis的環境信息 ,與spring集成后,該信息由spring來管理--> <environments default="development"> <environment id="development"> <!-- 配置JDBC事務控制,由mybatis進行管理 --> <transactionManager type="JDBC"></transactionManager> <!-- 配置數據源,采用dbcp連接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> </configuration>
3.1.3.建立JavaBean對象.
3.1.4.建立Mapping映射文件
在config下建立一個包叫做sqlmap方便管理映射文件.在該包下建立一個User.xml文件.它作為配置映射的文件.配置了sql語句的詳細信息.User.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"> <!-- namespace是命名空間,可以分類管理sql --> <mapper namespace="test1"> <!-- select標識一個MappedStatement --> <!-- id:statement的唯一標識. --> <!-- parameterType:指定輸入參數的Java類型.由於采用的是根據id查詢.指定int --> <!-- resultType:指定單條記錄的類型.(例如:select * from user指定的resultType依然為User類) --> <!-- 標簽主體里寫sql語句.注意#{}里接受輸入的參數類型.如果輸入的參數類型為基本的數據類型. 那么#內的內容可以任意.#{}會對輸入類型進行解釋.例如如果指定ParameterType為java.lang.String, 那么#{}會默認為輸入的值加上'' --> <select id="findUserById" parameterType="int" resultType="com.xyy.po.User"> SELECT * FROM USER WHERE id=#{id} </select> </mapper>
3.1.5.在SqlMapConfig.xml中配置mapping映射文件.
3.1.6.建立測試類進行測試
public class TestMyBatis1 { @Test public void testMyBatisById () throws IOException { //加載SqlMapConfig.xml配置文件 InputStream in=Resources.getResourceAsStream("SqlMapConfig.xml"); //創建SqlSessionFactory SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in); //創建SqlSession SqlSession session = factory.openSession(); //利SqlSession完成查詢操作,第一個參數是MappedStatement的id.注意namespace和配置的id唯一確定id.第二個參數是輸入參數,對應配置文件的parameterType User user = session.selectOne("test1.findUserById", 1); System.out.println(user); //關閉SqlSession session.close(); } }
3.2 通過mybatis完成通過name模糊查詢用戶(user)
3.2.1 建立MappedStatement標簽.此處為<select>
需要注意的是.這里用到了${}符號,它相當於連接符,不會對輸入的類型進行類型解釋.但是它無法有效的防止SQL注入!
<select id="findUserLikeUsername" parameterType="java.lang.String" resultType="com.xyy.po.User"> SELECT * FROM USER WHERE username LIKE '%${value}%' </select>
3.2.2 建立測試.
@Test public void testMyBatisByLike() throws IOException { InputStream in=Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in); SqlSession session = factory.openSession(); List<User> users=session.selectList("test1.findUserLikeUsername","小明"); System.out.println(users); session.close(); }
3.3 利用mybatis完成插入用戶的操作
3.3.1 編寫sql語句的映射
<!-- insert語句用的是insert標簽.注意沒有返回值可以不應寫resultType --> <insert id="insertUser" parameterType="com.xyy.po.User"> <!-- 使用#{屬性名}可以獲取傳入的實體bean對象中的對應的屬性值.由於數據庫表中id是自動遞增的 因此不用插入主鍵id --> INSERT INTO USER (username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address}); </insert>
3.3.2 建立測試類
注意對於增,刪,改操作.需要手動提交事務但是不需要手動開啟事務,事務在建立SqlSessionFactory的時候已經自動開啟了
public void testMyBatisInsert() throws IOException { InputStream in=Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in); SqlSession session = factory.openSession(); User user=new User(); user.setUsername("hlhdidi"); user.setAddress("北京昌平"); session.insert("test1.insertUser", user); session.commit();//提交事務 session.close(); }
3.4 返回主鍵
3.4.1 配置文件的書寫
有時候會有一些應用場景需要返回剛剛生成的主鍵.這就涉及到一個新的標簽.<selectKey>
Selectkey可以用於返回主鍵.它用於執行指定的sql.然后將返回結果封裝到輸入參數(通常是一個JavaBean)的指定屬性里.在下面的代碼中,selectKey中的order屬性指定為after是因為先插入數據,mysql數據庫才會分配id.
SELECT LAST_INSERT_ID()才能返回剛插入數據的主鍵
insert id="insertUser" parameterType="com.xyy.po.User"> <!-- selectkey:指定了查詢主鍵的sql.查詢的主鍵將會被封裝在傳入的參數的keyProperty指定屬性中 --> <!-- resultType返回的主鍵的類型 --> <!-- order:指定查詢主鍵發生在下面的sql語句的前面還是后面 --> <selectKey keyProperty="id" resultType="int" order="AFTER"> SELECT LAST_INSERT_ID(); </selectKey> <!-- 使用#{屬性名}可以獲取傳入的實體bean對象中的對應的屬性值.由於數據庫表中id是自動遞增的 因此不用插入主鍵id --> INSERT INTO USER (username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address}); </insert>
3.4.2 測試
@Test public void testMyBatisInsert() throws IOException { InputStream in=Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in); SqlSession session = factory.openSession(); User user=new User(); user.setUsername("hlhdidi"); user.setAddress("北京昌平"); session.insert("test1.insertUser", user); System.out.println(user.getId()); session.commit();//提交事務 session.close(); }
3.4.3 返回uuid類型的主鍵.
這種情況與上面情況的區別在於uuid是由我們指定並賦值到JavaBean的對應屬性的,因此執行的order需要是BEFORE.只有這樣才能先賦值,再插入數據庫.同時在下面的sql語句,同時書寫上#{id}
<!-- 需要在Insert語句之前.才能查詢出來並封裝到user的屬性. --> <selectKey keyProperty="id" resultType="String" order="BEFORE"> SELECT UUID(); </selectKey> INSERT INTO USER VALUES(#{id},#{username},#{birthday},#{sex},#{address});
3.4.4 利用序列產生主鍵.(oracle數據庫)
Oracle數據庫生成主鍵的方式是調用序列的nextval方法.我們可以用下面的方法去生成主鍵:
4.傳統Dao開發和Mapper開發.
4.1 傳統的Dao開發
SqlSessionFactory有Dao外部的程序注入進來.需要注意SqlSessionFactory通常是單例的:
public class UserDaoImpl implements UserDao{ private SqlSessionFactory factory; public UserDaoImpl(SqlSessionFactory factory) { this.factory=factory; } @Override public User findUserById(Integer id) { SqlSession session=factory.openSession(); return session.selectOne("test1.findUserById",id); } @Override public List<User> findUsersByName(String name) { SqlSession session=factory.openSession(); return session.selectList("test1.findUserLikeUsername", name); } @Override public void saveUser(User user) { SqlSession session=factory.openSession(); session.insert("test1.insertUser", user); } }
測試類體現了SqlSessionFactory單例的思想..
private SqlSessionFactory factory;//應當是單例的. @Before public void init() { try { InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); factory=new SqlSessionFactoryBuilder().build(in); } catch (IOException e) { e.printStackTrace(); } } @Test public void testDao() { UserDaoImpl udao=new UserDaoImpl(factory); User user=udao.findUserById(16); System.out.println(user); }
4.2 Mapper開發
4.2.1 規范
Mapper開發通過開發Mapper接口來替代傳統的Dao的開發方式.Mapper開發是mybatis最常用的開發方式!Mapper接口的實現類由mybatis通過jdk動態代理去實現.Mapper接口需要遵循以下開發規范:
1. mapper接口的全限定名要和mapper映射文件的namespace保持一致.(方便找出對應的mapper建立動態代理)
2. mapper接口的方法需要和mapper映射文件的statement的id保持一致.(方便找出對應的statement來執行sql語句)
3. mapper接口的方法的參數類型要和mapper映射文件的statement的parameterType值保持一致.
4. Mapper接口的方法的返回值類型要和mapper映射文件的statement的resultType保持一致.
4.2.2 mapper接口的編寫.
只需要是一個接口即可.此外注意mapper的規范!
public interface UserMapper { public User findUserById(Integer id); public void insertUser(User user); }
4.2.3 映射文件的編寫
和之前的User.xml的編寫基本保持一致.需要注意的是需要符合規范!(在下面的標識處)
4.2.4 測試
@Test public void testMapper() { SqlSession session = factory.openSession(); UserMapper mapper = session.getMapper(UserMapper.class);//建立代理對象 User user = mapper.findUserById(1); System.out.println(user); }