ByxOrm——模仿MyBatis的輕量級(jí)ORM框架

ByxOrm是一個(gè)模仿MyBatis設(shè)計(jì)的輕量級(jí)ORM框架托修,支持以下特性:

  • 使用動(dòng)態(tài)代理生成Dao接口的實(shí)現(xiàn)類
  • 使用注解配置Dao方法對(duì)應(yīng)的SQL語句
  • 使用注解配置實(shí)體類字段與數(shù)據(jù)庫列名的對(duì)應(yīng)關(guān)系
  • 動(dòng)態(tài)查詢和動(dòng)態(tài)更新

項(xiàng)目地址:https://github.com/byx2000/byx-orm

Maven引入

<repositories>
    <repository>
        <id>byx-maven-repo</id>
        <name>byx-maven-repo</name>
        <url>https://gitee.com/byx2000/maven-repo/raw/master/</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>byx.orm</groupId>
        <artifactId>byx-orm</artifactId>
        <version>1.0.0</version>
    </dependency>
</dependencies>

開啟-parameters編譯選項(xiàng)

由于ByxOrm運(yùn)行過程中需要讀取方法參數(shù)名,所以需要在pom.xml中啟用-parameters編譯選項(xiàng):

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <compilerArgs>
                    <arg>-parameters</arg>
                </compilerArgs>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <compilerVersion>${java.version}</compilerVersion>
                <encoding>${project.build.sourceEncoding}</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

快速入門

通過一個(gè)簡(jiǎn)單的例子來快速了解ByxOrm的特性增炭。

首先在數(shù)據(jù)庫中創(chuàng)建一個(gè)user表烟阐,并插入如下數(shù)據(jù):

u_id u_username u_password
1 aaa 123
2 bbb 456
3 ccc 789

導(dǎo)入數(shù)據(jù)庫驅(qū)動(dòng)類和連接池依賴搬俊,在啟動(dòng)類中寫一個(gè)方法用來返回DataSource

public class Main {
    private static DataSource dataSource() {
        // 返回一個(gè)DataSource ...
    }

    public static void main(String[] args) {
        // ...
    }
}

編寫用戶實(shí)體類User紊扬,并配置字段名與列名的映射:

public class User {
    @Column("u_id")
    private Integer id;

    @Column("u_username")
    private String username;

    @Column("u_password")
    private String password;

    // 省略getters、setters和toString ...
}

編寫數(shù)據(jù)訪問接口UserDao唉擂,并配置每個(gè)方法的SQL語句:

public interface UserDao {
    /**
     * 查詢所有用戶餐屎,返回列表
     */
    @Query("SELECT * FROM user")
    List<User> listAll();

    /**
     * 查詢指定id的用戶,返回單個(gè)對(duì)象
     */
    @Query("SELECT * FROM user WHERE u_id = #{id}")
    User getById(Integer id);

    /**
     * 多條件查詢用戶玩祟,動(dòng)態(tài)構(gòu)造SQL語句
     */
    @DynamicQuery(type = SqlProvider.class, method = "query")
    List<User> query(String username, String password);

    /**
     * 查詢用戶總數(shù)
     */
    @Query("SELECT COUNT(0) FROM user")
    int count();

    /**
     * 插入用戶腹缩,無返回值
     */
    @Update("INSERT into user(u_username, u_password) " +
            "VALUES(#{user.username}, #{user.password})")
    void insert(User user);

    /**
     * 刪除指定id的用戶,返回影響行數(shù)
     */
    @Update("DELETE FROM user WHERE u_id = #{id}")
    int delete(Integer id);

    class SqlProvider {
        /**
         * 提供動(dòng)態(tài)查詢SQL
         */
        public String query(String username, String password) {
            return new SqlBuilder(){
                {
                    select("*");
                    from("user");
                    if (username != null) {
                        where("u_username = #{username}");
                    }
                    if (password != null) {
                        where("u_password = #{password}");
                    }
                }
            }.build();
        }
    }
}

main函數(shù)中依次測(cè)試UserDao中的各個(gè)方法:

public static void main(String[] args) {
    // 生成UserDao的實(shí)現(xiàn)類
    UserDao userDao = new DaoGenerator(dataSource()).generate(UserDao.class);

    System.out.println("查詢所有用戶列表:");
    List<User> users = userDao.listAll();
    for (User u : users) {
        System.out.println(u);
    }

    System.out.println("查詢id為2的用戶:");
    User user = userDao.getById(2);
    System.out.println(user);

    System.out.println("查詢用戶名為ccc的用戶:");
    users = userDao.query("ccc", null);
    for (User u : users) {
        System.out.println(u);
    }

    System.out.println("插入用戶:");
    user.setUsername("byx");
    user.setPassword("666");
    userDao.insert(user);

    System.out.println("查詢用戶總數(shù):");
    System.out.println(userDao.count());

    System.out.println("刪除id為1的用戶:");
    int row = userDao.delete(1);
    System.out.println("影響行數(shù):" + row);

    System.out.println("查詢所有用戶列表:");
    users = userDao.listAll();
    for (User u : users) {
        System.out.println(u);
    }
}

控制臺(tái)輸出如下:

查詢所有用戶列表:
sql: SELECT * FROM user
User{id=1, username='aaa', password='123'}
User{id=2, username='bbb', password='456'}
User{id=3, username='ccc', password='789'}
查詢id為2的用戶:
sql: SELECT * FROM user WHERE u_id = 2
User{id=2, username='bbb', password='456'}
查詢用戶名為ccc的用戶:
sql: SELECT * FROM user WHERE u_username = 'ccc'
User{id=3, username='ccc', password='789'}
插入用戶:
sql: INSERT into user(u_username, u_password) VALUES('byx', '666')
查詢用戶總數(shù):
sql: SELECT COUNT(0) FROM user
4
刪除id為1的用戶:
sql: DELETE FROM user WHERE u_id = 1
影響行數(shù):1
查詢所有用戶列表:
sql: SELECT * FROM user
User{id=2, username='bbb', password='456'}
User{id=3, username='ccc', password='789'}
User{id=4, username='byx', password='666'}

@Query注解

該注解用于指定查詢操作的SQL空扎,與MyBatis的@Select類似藏鹊,支持#{...}占位符。

使用@Query標(biāo)注的方法的返回值可以為以下形式:

返回值類型 說明
基本類型或String 查詢單個(gè)值或結(jié)果總數(shù)
JavaBean 查詢單行转锈,并把該行數(shù)據(jù)轉(zhuǎn)換成JavaBean
List 查詢多行盘寡,每行封裝成一個(gè)JavaBean

例子:

public interface UserDao {
    // 查詢所有用戶
    @Query("SELECT * FROM user")
    List<User> listAll();

    // 根據(jù)id查詢用戶
    @Query("SELECT * FROM user WHERE id = #{id}")
    User getById(Integer id);

    // 查詢用戶總數(shù)
    @Query("SELECT COUNT(0) FROM user")
    int count();    
}

@Update注解

該注解用于指定更新操作的SQL,更新操作包括insert撮慨、update宴抚、delete,與MyBatis的Update甫煞、Insert菇曲、Delete類似,支持#{...}占位符抚吠。

使用@Update標(biāo)注的方法的返回值可以為以下形式:

返回值類型 說明
int 返回受影響行數(shù)
void 直接執(zhí)行操作常潮,什么也不返回

例子:

public interface UserDao {
    // 插入用戶
    @Update("INSERT INTO user(username, password) VALUES(#{user.username}, #{user.password})")
    int insert(User user);

    // 刪除用戶
    @Update("DELETE FROM user WHERE id = #{id}")
    void delete(Integer id);

    // 更新用戶名
    @Update("UPDATE user SET username = #{username} WHERE id = #{id}")
    void update(Integer id, String username);
}

@DynamicQuery注解

該注解用于動(dòng)態(tài)生成查詢SQL字符串,與MyBatis中的SelectProvider類似楷力,需要指定以下兩個(gè)屬性:

  • type: 生成SQL字符串的類
  • method: 生成SQL字符串的方法名

type中的method方法需要接收與對(duì)應(yīng)的Dao方法相同的參數(shù)列表喊式,并返回String類型。

例子:

public interface UserDao {
    // 根據(jù)用戶名或密碼查詢用戶
    @DynamicQuery(type = SqlProvider.class, method = "query")
    List<User> query(String username, String password);

    class SqlProvider {
        public String query(String username, String password) {
            return new SqlBuilder(){
                {
                    select("*");
                    from("user");
                    if (username != null) {
                        where("u_username = #{username}");
                    }
                    if (password != null) {
                        where("u_password = #{password}");
                    }
                }
            }.build();
        }
    }
}

注:

  1. DynamicQuerytype指定的類必須要有默認(rèn)構(gòu)造函數(shù)
  2. 如果DynamicQuery不指定method萧朝,則默認(rèn)使用被標(biāo)注方法的方法名
  3. 可以使用SqlBuilder來拼接SQL字符串岔留,用法與MyBatis的SQL類似
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市检柬,隨后出現(xiàn)的幾起案子献联,更是在濱河造成了極大的恐慌,老刑警劉巖何址,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件里逆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡用爪,警方通過查閱死者的電腦和手機(jī)原押,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來偎血,“玉大人诸衔,你說我怎么就攤上這事盯漂。” “怎么了笨农?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵宠能,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我磁餐,道長(zhǎng),這世上最難降的妖魔是什么阿弃? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任诊霹,我火速辦了婚禮,結(jié)果婚禮上渣淳,老公的妹妹穿的比我還像新娘脾还。我一直安慰自己,他們只是感情好入愧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布鄙漏。 她就那樣靜靜地躺著,像睡著了一般棺蛛。 火紅的嫁衣襯著肌膚如雪怔蚌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天旁赊,我揣著相機(jī)與錄音桦踊,去河邊找鬼。 笑死终畅,一個(gè)胖子當(dāng)著我的面吹牛籍胯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播离福,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼杖狼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了妖爷?” 一聲冷哼從身側(cè)響起蝶涩,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎絮识,沒想到半個(gè)月后子寓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笋除,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年斜友,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垃它。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鲜屏,死狀恐怖烹看,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情洛史,我是刑警寧澤惯殊,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站也殖,受9級(jí)特大地震影響土思,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜忆嗜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一己儒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捆毫,春花似錦闪湾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至濒憋,卻和暖如春何暇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凛驮。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工赖晶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人辐烂。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓遏插,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親纠修。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胳嘲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容