mybatis框架--学习笔记(上)
使用JDBC操作數據庫的問題總結:
(1)數據庫連接,使用時創建,不使用時立即釋放,對數據庫進行頻繁連接開啟和關閉,造成數據庫資源浪費,影響數據庫性能。
設想:使用數據庫連接池管理數據庫連接。
(2)將sql語句硬編譯到java代碼中,如果sql語句修改,需要重新編譯java代碼,不利于系統維護。
設想:將sql語句配置在xml配置文件中,即使sql變化,不需要對java代碼進行重新編譯。
(3)向preoaredStatement中設置參數,對占位符號位置和設置參數值,硬編譯在java代碼中,不利于系統維護。
設想:將sql語句和占位符號和參數全部配置在xml中。
(4)從resultSet中遍歷集數據時,存在硬編碼,將獲取表的字段進行硬編碼,不利于系統維護
設想:向查詢的結果集,自動映射成java對象。
1、mybatis入門程序:
(1)第一步:導入jar包。mybatis核心jar包,lib依賴包,數據庫驅動包。
(2)第二步:配置SqlMapConfig.xml文件:配置mybatis的運行環境,數據源,事務等。
<?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><environments default="development"><environment id="development"><!-- 使用jdbc事務管理,由mybatis管理--><transactionManager type="JDBC" /><!-- 配置數據庫連接池,由mybatis管理--><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></dataSource></environment></environments></configuration>db.properties文件:
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///mybatis_01 jdbc.username=root jdbc.password=admin(3)第三步:根據用戶id(主鍵)查詢用戶信息
public class User {private int id;private String username;private String sex;private Date birthday;private String address;//下面省略get和set方法 }映射文件(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進行分類化管理,理解sql隔離注意:使用mapper代理方法開發,namespace有特殊重要的作用--> <mapper namespace="test"><!-- 在映射文件中配置很多sql語句 --><!-- 1.通過id查詢數據庫的記錄 --><!-- 通過select執行數據庫查詢 id:標識映射文件中的sql,將sql語句封裝到mappedStatement對象中,所以將id稱為statement的id --><!-- parameterType:指定輸入參數的類型 --><!-- #{}表示一個占位符號#{id}:其中的id表示接收輸入的參數,參數的名稱就是id,如果輸入參數是簡單類型,#{}中參數名可以任意,可以value或其他名稱 --><!-- resultType:指定sql輸出結果的所映射java對象類型,select指定resultType表示將單條記錄映射成的java對象 --><select id="findUserById" parameterType="int" resultType="com.zwp.domain.User">SELECT * FROM USER WHERE id=#{id}</select> <!-- 2.根據用戶名稱模糊查詢用戶信息,可能返回多條用戶信息resultType:指定就是單挑記錄所映射的java對象類型${}:表示拼接sql串,接接收到的參數內容不加任何修飾拼接在sql中。使用${value}拼接sql,容易引起sql注入。${value}:接收輸入參數的內容,如果傳入類型是簡單類型,${}中只能使用value--><select id="findUserByName" parameterType="java.lang.String" resultType="com.zwp.domain.User"><!-- SELECT * FROM USER WHERE username like #{value} -->SELECT * FROM USER WHERE username like '%${value}%'</select><!-- 3.向數據庫插入數據 --><insert id="insertUser" parameterType="com.zwp.domain.User"><!-- 將插入數據的主鍵返回,返回到User對象中SELECT LAST_INSERT_ID():只適用于自增主鍵keyProperty:將查詢到的主鍵值設置到parameterType指定對象的哪個屬性order:SELECT LAST_INSERT_ID()相對于insert語句的執行順序resultType:指定結果類型--><selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">SELECT LAST_INSERT_ID()</selectKey><!--非自增主鍵的返回:使用mysql的uuid()生成主鍵:<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">SELECT uuid()</selectKey> --><!-- 通過oracle的序列生成主鍵 --><!-- <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">SELECT 序列名.nextval() </selectKey> -->INSERT INTO USER(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})</insert><!-- 4.根據id刪除用戶 --><delete id="deleteUser" parameterType="java.lang.Integer">DELETE FROM USER WHERE id=#{id}</delete><!-- 5.根據id更新用戶 --><update id="updateUser" parameterType="com.zwp.domain.User"><!-- id必須存,要修改的用戶id也包含在User對象中 -->UPDATE USER SET username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} WHERE id=#{id}</update></mapper>(4)第四步:在SqlMapConfig.xml中加載映射文件
<mappers><!-- 通過resource加載單個映射文件 --><mapper resource="config/sqlmap/User.xml"></mapper> </mappers> (5)第五步:編寫程序:public class MybatisFirst {//根據id得到一條用戶記錄@Testpublic void findUserById() throws IOException{//mybits配置文件String resource="SqlMapConfig.xml";//得到配置文件流InputStream inputStream=Resources.getResourceAsStream(resource);//創建會話工廠SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);//通過會話工廠得到SqlSessionSqlSession sqlSession=sqlSessionFactory.openSession();//通過SqlSession操作數據庫//第一個參數:映射文件中statement的id,等于namespace+"."+statement的id//第二個參數:指定和映射文件中所匹配的parameterType類型的參數User user=sqlSession.selectOne("test.findUserById", 1);System.out.println(user);//釋放資源sqlSession.close();}//根據用戶名模糊查詢@Testpublic void findUserByName() throws IOException{String resource="SqlMapConfig.xml";InputStream inputStream=Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession=sqlSessionFactory.openSession();//List<User> list=sqlSession.selectList("test.findUserByName", "%先生%");List<User> list=sqlSession.selectList("test.findUserByName", "先生");for(User user:list){System.out.println(user.getId()+user.getUsername());}sqlSession.close();}//插入用戶@Testpublic void insertUser() throws IOException{String resource="SqlMapConfig.xml";InputStream inputStream=Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession=sqlSessionFactory.openSession();User user=new User();user.setUsername("張同學");user.setBirthday(new Date());user.setSex("男");user.setAddress("汕頭");sqlSession.insert("test.insertUser",user);//事務提交sqlSession.commit();System.out.println(user.getId());//打印插入后的user用戶的idsqlSession.close();}//根據用戶id刪除用戶@Testpublic void deleteUser() throws IOException{String resource="SqlMapConfig.xml";InputStream inputStream=Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession=sqlSessionFactory.openSession();sqlSession.delete("test.deleteUser",6);sqlSession.commit();sqlSession.close();}//根據id修改用戶@Testpublic void updateUser() throws IOException{String resource="SqlMapConfig.xml";InputStream inputStream=Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession=sqlSessionFactory.openSession();User user=new User();user.setId(10);//id必須存在user.setUsername("修改后的張同學");user.setBirthday(new Date());user.setSex("男");user.setAddress("汕頭");sqlSession.update("test.updateUser",user);sqlSession.commit();sqlSession.close();} }
小結:
(1)parameterType:在映射文件中通過parameterType指定輸入參數的類型
(2)resultType:在映射文件中通過resultType指定輸出結果類型
(3)#{}和${}
#{}表示一個占位符號,參數可以是簡單類型。參數是簡單類型是時,命名無要求,可以是value或者其他值
${}表示一個拼接符號,會引入sql注入,所以不建議使用,參數可以是簡單類型。參數是簡單類型是時,命名只能是value。
(4)selectOne和selectList
--selectOne表示查詢出一條記錄進行映射。如果使用selectOne可以實現,使用selectList也可以實現(List集合中只有一個對象)
--selectList表示查詢出一個列表(多條記錄)進行映射,如果使用selectList查詢可以實現,不可以使用selectOne實現。
2、mybatis和hibernate本質區別和應用場景:
Hibernate:是一個標準的ORM框架(對象關系映射),不需要程序員寫sql,sql語句自動生成了。對sql語句進行優化、修改比較困難
應用場景:使用于需求與變化不多的中小型項目,
Mybatis:專注于sql本身,需要程序員自己編寫sql語句,修改比較方便。Mybatis是一個不完全的ORM框架,雖然需要程序員自己編寫sql,mybatis也可以實現映射(輸入映射,輸入映射)
應用場景:使用于需求變化較多的項目,比如:互聯網項目。
3、SqlSession:
SqlSession是一個面向用戶的接口,線程不安去,在SqlSession實現類中除了有接口中的方法(操作數據庫的方法)還有數據域屬性。SqlSession最佳應用場合是在方法體內,定義成員局部變量使用。
4、原始dao開發方法:(程序員自己寫dao和dao接口實現類)
(1)寫dao接口和dao接口實現類:
(2)需要向dao實現類中注入SqlSessionFactory,在方法體內通過SqlSessionFactory創建SqlSession。
//Dao接口 public interface UserDao {//根據id查詢用戶public User findUserById(int id) throws IOException;//添加用戶信息//刪除用戶信息 } //Dao接口實現類 public class UserDaoImpl implements UserDao{//注入SqlSessionFactory對象,通過構造函數方法注入:private SqlSessionFactory sqlSessionFactory;public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory = sqlSessionFactory;}@Overridepublic User findUserById(int id) throws IOException {SqlSession sqlSession=sqlSessionFactory.openSession();User user=sqlSession.selectOne("test.findUserById", id);sqlSession.close();return user;}} public class MybatisDaoTest {private SqlSessionFactory sqlSessionFactory;@Before//表示在其他方法之前執行public void set() throws Exception{String resource="SqlMapConfig.xml";//得到配置文件流InputStream inputStream=Resources.getResourceAsStream(resource);//創建會話工廠sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void findUserById() throws Exception{UserDao userdao=new UserDaoImpl(sqlSessionFactory);//注入sqlSessionFactoryUser user=userdao.findUserById(10);System.out.println(user.getId()+user.getUsername());} }(3)總結原始dao開發問題:
①dao接口實現類方法中存在大量模板方法,加入能將這些代碼提取出來,將會大大減輕程序員的工作量。
②調用sqlsession方法時將statement的id硬編碼了。
③調用sqlsession方法時傳入的變量,由于sqlsession方法使用泛型,即使變量類型傳入錯誤,在編譯階段也不報錯,不利于程序員開發。
5、Mapper代理開發方法:
(1)程序員需要編寫mapper.xml文件
(2)程序員編寫mapper接口(相當于dao接口),需要遵循一些開發規范,mybatis可以自動生成mapper接口實現類代理對象。
(3)引入配置文件
開發規范:
①在mapper.xml中,namespace等于mapper接口地址
②mapper.java接口中方法名和mapper.xml中的statement的id一致
③mapper.java接口中方法的輸入參數類型和mapper.xml中statement的parameterType指定的類型一致
④mapper.java接口中方法的返回值類型和mapper.xml中statement中resultType指定類型一致。
public interface UserMapper {/*(1)mapper.java接口中方法名和mapper.xml中的statement的id一致(2)mapper.java接口中方法的輸入參數類型和mapper.xml中statement的parameterType指定的類型一致(3)mapper.java接口中方法的返回值類型和mapper.xml中statement的resultment中resultType指定類型一致。*///根據id查詢用戶public User findUserById(int id) throws IOException;//根據用戶名進行模糊查詢public List<User> findUserByName(String username) throws IOException;//插入數據public void insertUser(User user) throws IOException;//根據用戶Id刪除用戶public void deleteUser(int id) throws IOException;//根據用戶id修改用戶public void updateUser(User user) throws IOException; } public class UserMapperTest {private SqlSessionFactory sqlSessionFactory;@Beforepublic void set() throws Exception{String resource="SqlMapConfig.xml";//得到配置文件流InputStream inputStream=Resources.getResourceAsStream(resource);//創建會話工廠sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void test1() throws IOException{SqlSession sqlSession=sqlSessionFactory.openSession();//創建UserMapper對象,mybatis自動生成mapper代理對象UserMapper userMapper=sqlSession.getMapper(UserMapper.class);User user=userMapper.findUserById(10);System.out.println(user.getUsername()+" "+user.getSex());} }
在SqlMapConfig.xml配置文件中加載映射文件:
<mappers><!-- 通過resource加載單個映射文件 --><mapper resource="config/sqlmap/User.xml"></mapper><mapper resource="config/sqlmap/UserMapper.xml"></mapper> </mappers>6、相關配置說明:
6.1、setting全局參數配置:
比如開啟二級緩存,開啟延遲加載
6.2、typeAliases(別名)--重點
在mapper.xml中,需要定義很多statement,在statement中,需要通過parameterType指定輸入類型、需要通過resultType指定輸出結果的映射類型。
如果在指定輸入輸出類型的全路徑,不方便開發。可以通過在mapper.xml文件通過定義別名,方便開發
(1)單個定義
(2)批量定義
<!-- 定義別名 --> <typeAliases><!-- 單個定義: type:類型的路徑 alias:別名 --><typeAlias type="com.zwp.domain.User" alias="user" /> <!-- 批量定義:指定包名,mybatis自動掃描包中的類,自動定義別名,別名就是類名,首字母大小寫都可以--><package name="com.zwp.domain"/> </typeAliases>6.3、typeHandlers(類型處理器):
mybatis中通過typeHandles完成jdbc類型和java類型的轉化。通常情況下,mybatis提供的類型處理器滿足日常需要,不需要自定義。6.4、mappers(映射配置)
(1)通過resource加載單個映射文件
(2)使用class通過mapper接口加載映射文件
(3)使用package通過包名批量加載
<!-- 加載映射文件 --> <mappers><!-- 通過resource加載單個映射文件 --><!-- <mapper resource="config/sqlmap/User.xml"></mapper> --><!-- <mapper resource="config/sqlmap/UserMapper.xml"></mapper> --><!-- 通過mapper接口加載單個映射文件遵循規范:需要mapper接口類名和mapper.xml映射文件名稱一致,且在同一目錄下上面規范的前提:使用mapper代理開發 --><!-- <mapper class="com.zwp.Dao.UserMapper"/> --><!-- 通過包名批量加載映射文件 --><!-- 指定包名,mybatis自動掃描包中的所有的mapper接口進行加載遵循規范:需要mapper接口類名和mapper.xml映射文件名稱一致,且在同一目錄下上面規范的前提:使用mapper代理開發 --><package name="com.zwp.Dao"/> </mappers>6.5、輸入映射:
通過parameterType指定輸入參數的類型,類型可以是簡單參數,hashmap,pojo的包裝類型。
傳遞pojo的包裝對象:
需求:完成用戶信息的綜合查詢,需要傳入的查詢條件很復雜(可能包括用戶信息、其他信息,比如商品、訂單的),針對上邊的需求,建議使用自定義的包裝類。
步驟:
(1)pojo包裝類
//與數據庫表相對應的User類: public class User {private int id;private String username;private String sex;private Date birthday;private String address;//省略get和set方法 } //User拓展類 public class UserCustomer extends User {//可以在這個類中拓展用戶信信息 } //自定義的pojo包住類 public class UserQueryVo {//在這里包裝所需要查詢的條件private UserCustomer userCustomer;public UserCustomer getUserCustomer() {return userCustomer;}public void setUserCustomer(UserCustomer userCustomer) {this.userCustomer = userCustomer;} //也可以包裝其他的查詢條件,訂單、商品 }(2)mapper.xml
(3)mapper.java
public interface UserMapper {//用戶綜合查詢public List<UserCustomer> findUserList(UserQueryVo userQueryVo) throws IOException; }測試代碼:
????????//用戶綜合查詢@Testpublic void findUserListtest() throws IOException{SqlSession sqlSession=sqlSessionFactory.openSession();//創建UserMapper對象,mybatis自動生成mapper代理對象UserMapper userMapper=sqlSession.getMapper(UserMapper.class);UserQueryVo userQueryVo=new UserQueryVo();UserCustomer userCustomer=new UserCustomer();userCustomer.setSex("男");userCustomer.setUsername("小鵬");userQueryVo.setUserCustomer(userCustomer);List<UserCustomer> list=userMapper.findUserList(userQueryVo);System.out.println(list);}6.6、輸出映射(resultType):
使用resultType進行輸出映射,只有查詢出來的列名和pojo中的屬性名一致,該列才可以映射成功。
如果查詢出來的列名和pojo中的屬性名全部不一致,沒有創建pojo對象。
如果查詢出來的列名和pojo的屬性有一個一致,就會創建pojo對象。
(1)輸出簡單類型:
用戶信息的綜合查詢列表總數,通過查詢總數和上邊用戶綜合查詢列表才可以實現分頁。
查詢出來的結果集只有一行且一列,就可以使用簡單類型進行輸出映射。
(2)輸出pojo對象和pojo列表:
不管是輸出的pojo單個對象還是一個列表,在mapper.xml中resultType指定的類型是一樣的,在mapper.java指定的方法返回類型不一樣。
????①輸出單個pojo對象,方法返回值是單個對象類型。
? ? ②輸出pojo對象的list,方法返回值是List<Pojo>
生成的動態代理對象的過程中,是根據mapper方法的返回值類型確定是調用selectOne(返回單個對象調用)還是調用selectList(返回集合對象調用)
6.7輸出映射(resultMap):
<!-- Type:resultMap最終映射的java類型,可以使用別名 id:resultMap的唯一標識 --><resultMap type="com.zwp.domain.User" id="resultMap1"><!-- id:查詢結果的唯一標識; column:查詢出來的列名; property:type指定pojo對象屬性名--><id column="id_" property="id"/><!-- 普通查詢類型 --><result column="username_" property="username"/></resultMap><select id="findUserByIdResultMap" parameterType="int" resultMap="resultMap1">SELECT id id_, username username_ FROM USER WHERE id=#{id}</select>小結:使用resultType進行輸出映射,只有查詢出來的列名和pojo中的屬性名一致,該列才可以映射成功。
如果查詢出來的列名和pojo的屬性名不一致,通過定義一個resultMap對列名和pojo屬性名之間作一個映射關系。
7、動態sql:
(1)if判斷:
(2)sql片段:
--定義sql片段:
<!-- 定義sql片段 --> <sql id="usersql"><!-- 建議:1、sql片段最好基于單表;2、不要把where定義進來 --><if test="userCustomer!=null"><if test="userCustomer.sex!=null">AND user.sex=#{userCustomer.sex}</if><if test="userCustomer.username!=null">AND user.username LIKE '%${userCustomer.username}%'</if> </if> </sql>--引入sql片段:
<if test="ids!=null"><!-- collection:指定輸入對象中屬性集合 item:每次遍歷生成的對象open:開始遍歷時拼接的串 close:結束遍歷時拼接的串separator:遍歷的兩個對象中需要拼接的串--> <!-- 實現查詢的sql語句:AND (id=1 OR id=5 OR id=7) --><foreach collection="ids" item="user_id" open="AND (" close=")" separator="OR">id=#{user_id}</foreach> </if> <if test="ids!=null"><!-- 實現查詢的sql語句:AND id In(1,5,7) --><foreach collection="ids" item="user_id" open="AND id IN(" close=")" separator=",">#{user_id}</foreach> </if> //自定義的pojo包住類 public class UserQueryVo {//在這里包裝所需要查詢的條件//用戶查詢條件private List<Integer> ids;//添加條件集合private UserCustomer userCustomer;public List<Integer> getIds() {return ids;}public void setIds(List<Integer> ids) {this.ids = ids;}public UserCustomer getUserCustomer() {return userCustomer;}public void setUserCustomer(UserCustomer userCustomer) {this.userCustomer = userCustomer;}//也可以包裝其他的查詢條件,訂單、商品 } //用戶綜合查詢@Testpublic void findUserListtest() throws IOException{SqlSession sqlSession=sqlSessionFactory.openSession();//創建UserMapper對象,mybatis自動生成mapper代理對象UserMapper userMapper=sqlSession.getMapper(UserMapper.class);UserQueryVo userQueryVo=new UserQueryVo();UserCustomer userCustomer=new UserCustomer();userCustomer.setSex("男");userCustomer.setUsername("小鵬");List<Integer> ids=new ArrayList<Integer>();ids.add(1);ids.add(5);ids.add(7);userQueryVo.setIds(ids);userQueryVo.setUserCustomer(userCustomer);int count=userMapper.findUserCount(userQueryVo);List<UserCustomer> list=userMapper.findUserList(userQueryVo);System.out.println(count);System.out.println(list);}
下篇:mybatis框架--學習筆記(下):https://blog.csdn.net/a745233700/article/details/81035781
總結
以上是生活随笔為你收集整理的mybatis框架--学习笔记(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring配置c3p0连接池、spri
- 下一篇: mybatis框架--学习笔记(下)